「ブックマーク一覧ジャンプ」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
sukemaru版(通常版/include版)を増補改訂
Sukemaru (トーク | 投稿記録)
sukemaru 版: 改訂版。ZIP 書庫を更新
122行目: 122行目:
* ポップアップメニューだと読み取りづらい半角英小文字・と ascii 記号の一部を全角で表示。
* ポップアップメニューだと読み取りづらい半角英小文字・と ascii 記号の一部を全角で表示。
<br>
<br>
[[ファイル:Mery_ブックマークジャンプ(通常版)_SS.png|frameless|640px|thumb|submenuenable = 2]]
[[ファイル:Mery_ブックマークジャンプ(通常版)_SS.png|frameless|640px|thumb|ブックマークジャンプ(通常版)]]
<br clear=all>
<br clear=all>




: Mery でプログラミング用のフォントを使っている人だと、ポップアップメニュー内で半角 <q>'''¥'''</q> 記号 (U+005C) が'''バックスラッシュ''' (U+005C) にならないのは気落ち悪いかも? ということで、ソースコード内の関数 MenuKey() のコードのコメントアウトしてある行を有効化すると "擬似的に" '''バックスラッシュ'''化できます <br> (※ <q>'''∖'''</q> (U+2216) に置換して表示します)。
* Mery でプログラミング用のフォントを使っている人だと、ポップアップメニュー内で半角 <q>'''¥'''</q> 記号 (U+005C) が'''バックスラッシュ''' (U+005C) にならないのは気落ち悪いかも? ということで、ソースコード内の関数 MenuKey() のコードのコメントアウトしてある行(300行目付近)をアンコメントすると "擬似的に" '''バックスラッシュ'''化できます <br> (※ <q>'''∖'''</q> (U+2216) に置換して表示します)。
 
 
* 行番号の桁埋め(右寄せ/空白埋め)用の[https://ja.wikipedia.org/wiki/スペース#コンピュータにおけるスペース 空白文字]を設定する項目 <syntaxhighlight lang="javascript" inline>var blankChr = " ";</syntaxhighlight> を追加し、初期値を半角空白 <code>" "</code>(U+0020)にしました(※ これまで MS UI Gothic に最適化してあった桁埋め方法をカスタマイズできるようにした)。
: MS UI Gothic では2分アキ(EN SPACE) <code>"\u2002"</code><br> Meiryo UI では和字間隔(全角空白) <code>"\u3000"</code><br> Segoe UI では図形間隔(FIGURE SPACE) <code>"\u2007"</code> にすると具合がよいようです。
 


== ダウンロード ==
== ダウンロード ==


'''ダウンロード:''' 「[[ファイル:ブックマークジャンプ.zip]]」(アイコン入り) 
'''ダウンロード:''' 「[[ファイル:ブックマークジャンプ.zip]]」(アイコン入り) 
<br> 最終更新: 2019/12/05(Mery 2.7.0 以降への対応と [[#include版|include版]] を追加)
<br> 最終更新: 2020/06/24
: 【共通】:行番号の桁埋め用の空白文字を指定する設定項目などを追加
: 【include版】:分割サブメニューの表示形式のカスタマイズ用設定項目を追加
 
: オマケとして [ 編集 ] メニューのブックマーク関連コマンドのアイコン化用マクロ×4
: オマケとして [ 編集 ] メニューのブックマーク関連コマンドのアイコン化用マクロ×4


137行目: 145行目:
== ソースコード ==
== ソースコード ==


* このマクロではポップアップメニューの表示に EN SPACE <q> </q> (U+2002) などを使用します。ファイルに保存するさいは、文字コードを shift_JIS にしないでください('''UTF-8''' や Unicode で保存する)。
* このマクロではポップアップメニューの表示に unicode 文字を使用します。<br>
<source lang="javascript" style="height:80em; overflow:auto;" highlight="28-60">
ファイルに保存するさいは、文字コードを shift_JIS にしないでください('''UTF-8''' や Unicode で保存する)。
 
<source lang="javascript" style="height:80em; overflow:auto;" highlight="16-69,291">
#title = "ブックマーク一覧ジャンプ"
#title = "ブックマーク一覧ジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
148行目: 158行目:
  * 「ブックマーク一覧ジャンプ」
  * 「ブックマーク一覧ジャンプ」
  *  Orginal created by: Kuro, goat (2012/06/22 - 2012/09/24)
  *  Orginal created by: Kuro, goat (2012/06/22 - 2012/09/24)
  *  Modified by:        sukemaru  (2018/08/08 - 2019/12/05)
  *  Modified by:        sukemaru  (2018/08/08 - 2020/06/07)
  * ---------------------------------------------------------
  * ---------------------------------------------------------
* ブックマーク一覧をポップアップメニューで表示し、選択した行へジャンプする。
*
* ・ 行番号は "表示行" / "論理行" の設定可。
* ・ ブックマーク行の検索 ~ ポップアップメニュー表示 の速度を改善。
* ・ ポップアップメニューの体裁を変更。
* ・ ステータスバーに情報を表示。
* ・「ブックマークがありません」メニュー。
* ・ ジャンプしたときのスクロール位置を調整。
* ・ ジャンプ先まで範囲選択するときの先頭/末尾を調整。
* ・「先頭行/行頭/最終行 へジャンプ」をメニューにピン止め表示
* ・「ブックマークを設定/解除」をメニューの先頭にピン止め表示
*
  */
  */


var start = new Date(); // 所要時間計測(開始)
var start = new Date();   // 所要時間計測(開始)


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


// ■ ジャンプする前に選択範囲があったときはジャンプ先の行まで範囲選択する?
// ■ ジャンプする前に選択範囲があったときはジャンプ先の行まで範囲選択する?
var blockSelectEnable = false; // (true 範囲選択する / false 範囲選択しない)
var blockSelectEnable = false; // (true 範囲選択する / false 範囲選択しない)


     // ■ もとの選択範囲をジャンプ後の範囲選択に含める?
     // ■ もとの選択範囲をジャンプ後の範囲選択に含める?
     var keepInitialSelect = false; // (true 含める / false 含めない)
     var keepInitialSelect = false; // (true 含める / false 含めない)


     // ■ 下の行にジャンプしたとき、ジャンプ先の行全体(論理行)を選択範囲に含める?
     // ■ 下の行にジャンプしたとき、ジャンプ先の行全体(論理行)を選択範囲に含める?
     var endOfBookmarkLine = false; // (true 含める / false 含めない)
     var endOfBookmarkLine = false; // (true 含める / false 含めない)
 


// ■ 行番号の表示方法を Mery.ini から「自動」で読み込む?
// ■ 行番号の表示方法を Mery.ini から「自動」で読み込む?
var autoLineModeEnable = false; // (true 自動読み込み / false 手動設定)
var autoLineModeEnable = false; // (true 自動読み込み / false 手動設定)


     // ■ 行番号の表示方法(手動設定用)
     // ■ 行番号の表示方法(手動設定用)
     var lineColumnView = 0; // ( 0 論理行 / 1 表示行 )
     var lineColumnView = 0;   // ( 0 論理行 / 1 表示行 )
 


// ■ 「ブックマークがありません」メニューを表示する?
// ■ 「ブックマークがありません」メニューを表示する?
var extraMenuEnable = true; // (true 表示する / false 表示しない)
var extraMenuEnable = true; // (true 表示する / false 表示しない)


// ■ ポップアップメニューに「先頭行/最終行 へジャンプ」をピン止め表示する?
// ■ ポップアップメニューに「先頭行/最終行 へジャンプ」をピン止め表示する?
var menuPinEnable = true; // (true 表示する / false 表示しない)
var menuPinEnable = true; // (true 表示する / false 表示しない)
 
// ■ ポップアップメニュー内の 30件* ごとに「キャンセル」を表示する?
var menuScrollEnable = false;  // (true する / false しない)
 
    // ■ 「キャンセル」の挿入ピッチ
    // ※ 10 - 100 のあいだの範囲の 10 の倍数で指定すること
    var subMenuHeight = 30;  // ◆初期値 = 30;
 


// ■ ポップアップメニューに表示する文字数の目安
// ■ ポップアップメニューに表示する文字数の目安
var menuWidth = 65; // (全角/半角の区別なし)
var menuWidth = 65; // (全角/半角の区別なし)


// ■ 半角英文字を全角で表示する [!"%'(),.:;@\[\]`a-z{|}]
// ■ 半角英文字を全角で表示する [!"%'(),.:;@\[\]`a-z{|}]
var toFullWidth = true; // (true 置換する false 置換しない)
var toWideWidth = 0; // (0 しない 1 文字間を広げる / 2 全角にする)


// ■ ポップアップメニューを表示する位置
// ■ ポップアップメニューを表示する位置
var menuPosMouse = true; // ( true マウス位置 / false カーソル位置 )
var menuPosMouse = true; // ( true マウス位置 / false カーソル位置 )
 
 
// ■ 連番の桁埋め(右寄せ/空白埋め)用空白文字の定義
var blankChr = " ";  // " " or "\u2002" or "\u3000" or "\u2007" or ...
 
  /* 半角数字の幅に等しい空白文字として
    MS UI Gothic では「2分アキ」 = EN SPACE: "\u2002"
    (MeiryoKe_UI Gothic は MS UI Gothic に同じ)
    Meiryo UI では「和字間隔」 = 全角空白: "\u3000"
    Segoe UI では「図形間隔」 = FIGURE SPACE: "\u2007"
    にすると具合がよさそうですが、ウエイトによって幅が変わるので... */


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


// Mery.ini から「行の表示方法」を取得する( 表示行 = 1 / 論理行 = 0
// 連番の桁埋め(右寄せ/空白埋め)用
var b1 = ( ! blankChr || ( "" + blankChr ).length > 1 )
      ? " " : blankChr;
Object.prototype.PadSpace = function(len, chr) {
  var dgt = String(this);
  len = Number(len) || dgt.length;
  chr = chr ? chr.toString() : b1; // (b1 = blankChr || " ")
  if (len < 0 || len < dgt.length || chr.length !== 1)
    return dgt;
  for (var i = 0; i < len; i++)
    chr += chr;
  return (chr + dgt).slice( - len);
};
// Mery.ini から「行の表示方法」を取得する
if ( autoLineModeEnable ) {
if ( autoLineModeEnable ) {
   lineColumnView = GetIniOptionNum( "LineColumnView" );
   lineColumnView = GetIniOptionNum( "LineColumnView" );
210行目: 242行目:
var d = editor.ActiveDocument;
var d = editor.ActiveDocument;
var lines = d.GetLines( lineMode );
var lines = d.GetLines( lineMode );
var linesWidth = lines.toString().length;
// カーソルと選択範囲の位置を保存
// カーソルと選択範囲の位置を保存
var s = d.selection;
var s = d.selection;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var aY = s.GetActivePointY( posMode );
var ay = s.GetActivePointY( posMode );
var sX = ScrollX,  sY = ScrollY;
var sx = ScrollX,  sy = ScrollY;
// ブックマーク行の変数
// ブックマーク行の変数
var bmArray = [],  flag = 0,  isBookmarked = 0;
var bmArray = [],  bmY = 0,  bmStr = "",  label = "";
var bmY, bmStr;
// アクティブ行がブックマークされているか
var flag = 0, isBookmarked = 0;


// ブックマーク行を検索
// ブックマーク行を検索
227行目: 259行目:
   bmY = s.GetActivePointY( posMode );
   bmY = s.GetActivePointY( posMode );
   bmStr = d.GetLine( bmY, lineMode );
   bmStr = d.GetLine( bmY, lineMode );
   if ( bmY == aY ) { flag = 1; isBookmarked = 1; }
  label = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
   bmArray.push( [ MenuKey( bmStr, bmY ), bmY, flag ] );
   if ( bmY === ay ) { flag = 1; isBookmarked = 1; }
   bmArray.push( { str: label, id: bmY, flag: flag } );
}
}
// 2行目以降のブックマークを探す
// 2行目以降のブックマークを探す
235行目: 268行目:
   bmY = s.GetActivePointY( posMode );
   bmY = s.GetActivePointY( posMode );
   bmStr = d.GetLine( bmY, lineMode );
   bmStr = d.GetLine( bmY, lineMode );
   if ( bmY == aY ) { flag = 1; isBookmarked = 1; }
  label = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
   if ( bmY === ay ) { flag = 1; isBookmarked = 1; }
   else { flag = 0; }
   else { flag = 0; }
   bmArray.push( [ MenuKey( bmStr, bmY ), bmY, flag ] );
   bmArray.push( { str: label, id: bmY, flag: flag } );
}
}
// カーソル位置と選択範囲を復帰
s.SetActivePos( act );  s.SetAnchorPos( anc );
ScrollX = sx;  ScrollY = sy;
Redraw = true;
// ブックマークの件数
// ブックマークの件数
var bmCount = bmArray.length;
var bmCount = bmArray.length;
 
var numWidth = ( ( menuPinEnable || ! bmCount ) ? lines : bmY )
// カーソル位置と選択範囲を復帰
              .toString().length;
s.SetActivePos( act );
s.SetAnchorPos( anc );
ScrollX = sX,  ScrollY = sY;
Redraw = true;


// ステータスラベル
// ステータスラベル
var status1 = ( bmCount )
var status1 = ( bmCount )
            ? " ブックマーク: " + bmCount + " 件 /"
? " ブックマーク: "
            : " ブックマークがありません。";
  + bmCount.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
var status2 = " 全体の行数: "  
  + " 件 "
            + lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )  
: " ブックマークがありません。 ";
            + ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );
var status2 = ( bmCount ? "/ " : "" )
+ "全体の行数: "
+ lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
+ ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );
 
// アクティブ行のチェックマークフラグ (meMenuChecked = 1)
var Check = function( num ) { return ( num === ay ) *1; }
 
// ピン止めアイテム
var bmPin    = ay.PadSpace( numWidth ) + ": "
              + "ブックマークを設定/解除 (&B)";
var countPin  = "".PadSpace( numWidth )
              + " ▼ " + status1 + " ▼";
var cancelPin = "".PadSpace( numWidth )
              + " キャンセル\t& ";
var topPin    = ( 1 ).PadSpace( numWidth ) + ": "
              + "** 先頭行へジャンプ (&T) **";
var endPin    = lines.PadSpace( numWidth ) + ": "
              + "** 最終行へジャンプ (&E) **";
var actPin    = ay.PadSpace( numWidth ) + ": "
              + "** 行頭へジャンプ (&A) **";


// ポップアップメニューの準備
// ポップアップメニューの準備
var bmMenu = CreatePopupMenu();
var bmMenu = CreatePopupMenu();
// アクティブ行のチェックマーク (meMenuChecked)
var Check = function( num ) { return  ( num == aY ) *1; }
// ピン止めアイテム
var bmPin = ( "          " + aY ).slice( - linesWidth )
          + ":  ブックマークを設定/解除 (&B)";
if ( bmCount ) {
  var countPin = ( "          " ).slice( - linesWidth )
              + " ▼ " + status1.slice( 0, -1 ) + " ▼";
  var cancelPin = ( "          " ).slice( - linesWidth )
                + "  キャンセル\t& ";
}
if ( menuPinEnable ) {
  var topPin = ( "          " + 1 ).slice( - linesWidth )
            + ":  ** 先頭行へジャンプ (&T) **";
  var endPin = ( "          " + lines ).slice( - linesWidth )
            + ":  ** 最終行へジャンプ (&E) **";
  var actPin = ( "          " + aY ).slice( - linesWidth )
            + ":     行頭へジャンプ (&A)";
}


// 「ブックマークを設定/解除」をピン止め
// メニューの最上部に「設定/解除」をピン止め
if ( bmCount || extraMenuEnable ) {
if ( bmCount || extraMenuEnable ) {
   bmMenu.Add( bmPin, 20000000, isBookmarked );
   bmMenu.Add( bmPin, 20000000, isBookmarked );
   bmMenu.Add( "-----", 0, meMenuSeparator );
   bmMenu.Add( "----", 0, meMenuSeparator );
}
}


// 「ブックマーク一覧」ポップアップメニュー
// 「ブックマーク一覧」ポップアップメニュー
if ( bmCount ) {
if ( bmCount ) {
  bmMenu.Add( "----", 0, meMenuSeparator );
   // メニュー上部のピン止めアイテム
   // メニュー上部のピン止めアイテム
   bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
   if ( menuPinEnable
  bmMenu.Add( "-----", 0, meMenuSeparator );
  && ( bmArray[0].id > 1 || ! isBookmarked && ay > 1 && ay < lines ) ) {
  if ( menuPinEnable && bmArray[0][1] > 1 ) {
    if ( bmArray[0].id > 1 ) {
    bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
      bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
    }
    if ( ! isBookmarked && ay > 1 && ay < lines ) {
      bmMenu.Add( actPin, ay, meMenuChecked ); // 「行頭へジャンプ」
    }
    if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ].id !== lines ) {
      bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
    }
    bmMenu.Add( "----", 0, meMenuSeparator );
   }
   }
   if ( ! isBookmarked && aY > 1 && aY < lines ) {
   // ブックマーク一覧
    bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
   bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
  }
   for ( var i = 0, bm, num; i < bmCount; i ++ ) {
  bmMenu.Add( "-----", 0, meMenuSeparator );
     if ( i % 10 === 0 && i > 0 ) {
   bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
       bmMenu.Add( "----", 0, meMenuSeparator ); // 10行ごとにセパレータ
  // ブックマーク行をポップアップメニューに追加
      if ( menuScrollEnable && i % subMenuHeight === 0 ) {
   for ( var i = 0, flags; i < bmCount; i ++ ) {
        bmMenu.Add( cancelPin, 0 );  // 30行* ごとに「キャンセル」
     if ( i != 0 && i % 10 == 0 ) {
        bmMenu.Add( "----", 0, meMenuSeparator );
       bmMenu.Add( "-----", 0, meMenuSeparator ); // 10行ごとにセパレータ
      }
     }
     }
     bmMenu.Add( bmArray[i][0], bmArray[i][1], Check( bmArray[i][1] ) );
    // ブックマーク行をポップアップメニューに追加
    bm  = bmArray[i];
    num = bm.id.PadSpace( numWidth ).replace( /\d$/, "&$&: " );
     bmMenu.Add( num + bm.str, bm.id, Check( bm.id ) );
   }
   }
   // メニュー下部のピン止めアイテム
   // メニュー下部のピン止めアイテム
   if ( menuPinEnable && bmArray[ bmCount - 1 ][1] !== lines ) {
   if ( menuPinEnable && bmArray[ bmCount -1 ].id !== lines ) {
     bmMenu.Add( "-----", 0, meMenuSeparator );
     bmMenu.Add( "----", 0, meMenuSeparator );
     bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
     bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
  }
  if ( menuScrollEnable && bmCount > subMenuHeight ) {
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( cancelPin, 0 );  // 「キャンセル」
   }
   }
}
}
314行目: 365行目:
// 「ブックマークがありません」ポップアップメニュー
// 「ブックマークがありません」ポップアップメニュー
else if ( extraMenuEnable ) {
else if ( extraMenuEnable ) {
   bmMenu.Add( "※" + status1 + "& ※", 0 );
  // 「ブックマークがありません」
   bmMenu.Add( "※ " + status1 + " ※", 0, meMenuGrayed );
   if ( ! menuPinEnable ) {
   if ( ! menuPinEnable ) {
     bmMenu.Add( status2 + "& ", 0 );
     bmMenu.Add( " " + status2, 0 ); // 全体の行数
   }
   }
   // ピン止めアイテム
   // ピン止めアイテム
   else if ( lines > 1 ) {
   if ( menuPinEnable ) {
    bmMenu.Add( "-----", 0, meMenuSeparator );
    if ( lines > 1 ) {
    bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
      bmMenu.Add( "----", 0, meMenuSeparator );
    if ( aY > 1 && aY < lines ) {
      bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
       bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
      if ( ay > 1 && ay < lines ) {
        bmMenu.Add( actPin, ay, meMenuChecked );  // 「行頭へジャンプ」
      }
      bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
    }
    else {
       bmMenu.Add( actPin, ay, meMenuChecked ); // 「行頭へジャンプ」
     }
     }
    bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
  }
  else if ( lines == 1 ) {
    bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
   }
   }
}
}


// ステータスバーとポップアップメニューを表示
// ステータスとポップアップメニューを表示
Status = status1 + status2 + TimerStatus( new Date(), start );
Status = status1 + status2 + TimerElapsed( new Date(), start );
var y = bmMenu.Track( menuPosMouse );
var y = bmMenu.Track( menuPosMouse );


// ブックマークを設定/解除
// ブックマークを設定/解除
if ( y == 20000000 ) {
if ( y === 20000000 ) {
   editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
   editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}
}
// ジャンプ
// ジャンプ
else if ( y > 0 ) {
else if ( y ) {
  Redraw = false;
   s.SetActivePoint( posMode, 1, y );
   s.SetActivePoint( posMode, 1, y );
  var yy = s.GetActivePointY( mePosView );


   // アクティブ行へのジャンプではスクロール位置をリセット
   // アクティブ行へのジャンプではスクロール位置をリセット
   if ( y == aY ) { ScrollY = aY; }
   if ( y === ay ) { ScrollY = yy }
 
   // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
   // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
   if ( blockSelectEnable && act !== anc ) {
   if ( blockSelectEnable && act !== anc ) {
     var jumpDown = ( aY < y );
     var jumpDown = ( ay < y );
     // もとの選択範囲の文字列を含んだままにする
     // もとの選択範囲の文字列を含んだままにする
     if ( keepInitialSelect ) {
     if ( keepInitialSelect ) {
361行目: 416行目:
     if ( jumpDown && endOfBookmarkLine ) {
     if ( jumpDown && endOfBookmarkLine ) {
       s.EndOfLine( true, mePosLogical );
       s.EndOfLine( true, mePosLogical );
       ScrollX = 1; // 水平スクロールを左端にリセット
       ScrollX = 1;
     }
     }
   }
   }
   ScrollY = ( ScrollY == sY )
   ScrollY = ( ScrollY === sy ) ? sy : yy;
          ? sY : s.GetActivePointY( mePosView );
  Redraw = true;
}
}


// ---------- ▼ 関数 ▼ ---------- //
// ---------- ▼ 関数 ▼ ---------- //
/**
/**
  * 関数 MenuKey( str, num )
  * 関数 MenuKey( str, maxStrLength, toWideWidth, blankChr )
  * ポップアップメニューに表示するラベルを生成する
  * ポップアップメニューに表示するラベルを生成する
*
* ・行頭空白を除去、空白文字を圧縮
* ・「¥」(U+005C) を「∖」に置換: 「∖」(U+2216) または 「╲」(U+2572) 「﹨」(U+FE68)
* ・「&」 を補完
* ・「a-z」 と判別しづらいメタ文字を全角に置換  →  条件つきに変更
* ・文字数を切り詰め
* ・行番号をケタ埋め: EN SPACE 「 」(U+2002)
  */
  */
function MenuKey( str, num ) {
function MenuKey( str, menuWidth, toWideWidth, b1 ) {
   var menuKey = ( str ) ? /^[\t  ]+$/.test( str ) ? "( 空白行 )" : str
   var keyWidth = ( /^[\s ]*[\s!-~\u200A\u2216\u22A0\u25AF]+$/.test( str ) )
                        : "( 空行 )";
              ? Math.floor( menuWidth *1.2 ) : menuWidth;
   menuKey = menuKey.replace( /^[\t  ]+/, "" )
  var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
                  .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
  var key = str ? ( regBlankLine.test( str ) ? "( 空白行 )" : str )
                  .slice( 0, menuWidth *2 )
                : "( 空行 )";
                // .replace( /[\\]/g, "" )
   var regBlankChar = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g;
                  .replace( /&/g, "&&" );
  key = key.replace( /^[\s ]+/, "" )
   if ( toFullWidth ) {
          .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " \u203A " ) //「 › 」
     menuKey = menuKey.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
          .slice( 0, keyWidth + 1 )
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
          .replace( /&/g, "&&" )
        // .replace( /\\/g, "\u2216" )         //「∖」
          .replace( regBlankChar, "\u25AF" ); //「▯」
  // 半角英小文字と ascii記号を全角化
   if ( toWideWidth === 2 ) {
     key = key.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
     } );
     } );
   }
   }
   menuKey = ( menuKey.length > menuWidth )
   // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (\u200A) を付加
          ? menuKey.slice( 0, menuWidth ) + " ..." : menuKey;
  else if ( toWideWidth === 1 ) {
   return ( "          &" + num ).slice( - linesWidth - 1 ) + ":  " + menuKey;
    key = key.replace( /[!-%'-.:-@\[-`{-~fijl\u00A5\u22A0\u25AF]|&&/g,
              "\u200A$&\u200A" )
            .replace( /\u200A+/g, "\u200A" )
            .replace( RegExp( b1 + "\u200A", "g" ), b1 );
    keyWidth += ( key.match( /[\u200A\u203A]|&&/g ) || "" ).length;
  }
  key = ( key.length > keyWidth )
      ? key.slice( 0, keyWidth ) + " ..." : key;
   return key;
}
}


/**
/**
  * 関数 TimerStatus( end, start )
  * 関数 TimerElapsed( end, start )
  * start からの経過時間計測
  * start からの経過時間を [ s. sss 秒 ] で返す
* [ s. sss 秒 ] で返す
  */
  */
function TimerStatus( end, start ) {
function TimerElapsed( end, start ) {
   var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
   var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
   return "  [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
   return "  [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
418行目: 477行目:
   // Mery.ini を探す
   // Mery.ini を探す
   var meryPath = editor.FullName;
   var meryPath = editor.FullName;
  var mery    = Fso.GetBaseName( meryPath );
   var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
   var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
   if ( ! Fso.FileExists( iniPath ) ) {
   if ( ! Fso.FileExists( iniPath ) ) {
     var WshShell = new ActiveXObject( "WScript.Shell" );
     var mery = Fso.GetBaseName( meryPath );
    iniPath = WshShell.SpecialFolders( "APPDATA" )
    iniPath = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
             + "\\Mery\\" + mery + ".ini";
             + "\\Mery\\" + mery + ".ini";
   }
   }
429行目: 488行目:
   var iniText = iniFile.ReadAll();
   var iniText = iniFile.ReadAll();
   iniFile.Close();
   iniFile.Close();
   // 項目の値を返す
   // 項目の値を取得する
   return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
   return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
}
}
/**
* ---------- ▼ 更新履歴 ▼ ----------
* 2019/03/29:
* ・sukemaru版をマクロライブラリに投稿。
* 2019/04/08:
* ・Quit() の削除と、軽微な変更。
* 2019/04/16:
* ・Mery 2.7.0 でのブックマークの仕様変更に対応。【include版】を追加。
* 2019/12/05:
* ・「ブックマークを設定/解除」 をメニューに追加
* ・メニュー内にブックマーク件数を表示
* ・「メニューを表示する位置」 の設定を追加
* ・「もとの選択範囲をジャンプ後の範囲選択に含める」 を設定項目に追加
* ・【include版】を大幅に変更。
*/
</source>
</source>


453行目: 496行目:
== include版 ==
== include版 ==


*[[ダウンロード|ZIP 書庫]]内の「'''include版'''」フォルダの JS ファイルを使用すると、「[[ポップアップメニューで検索先にジャンプ#include版|ポップアップメニューで検索先にジャンプ]]」マクロと同様に、<span style="color:#c00;">マクロの動作設定の変更をポップアップメニュー内の項目のチェック ON/OFF でできるようになります。 </span>
* [[ダウンロード|ZIP 書庫]]内の「'''include版'''」フォルダの JS ファイルを使用すると、「[[ポップアップメニューで検索先にジャンプ#include版|ポップアップメニューで検索先にジャンプ]]」マクロと同様に、<span style="color:#c00;">マクロの動作設定の変更をポップアップメニュー内の項目のチェック ON/OFF でできるようになります。 </span>
<br>
<br>
[[ファイル:Mery_ブックマークジャンプ_SS(1).png|link=https://www.haijin-boys.com/wiki/images/9/96/Mery_%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%82%B8%E3%83%A3%E3%83%B3%E3%83%97_SS.png|設定変更サブメニュー]]
[[ファイル:Mery_ブックマークジャンプ_SS(1).png|link=https://www.haijin-boys.com/wiki/images/9/96/Mery_ブックマークジャンプ_SS.png|設定変更サブメニュー]]
<br clear=all><br>
<br clear=all><br>
[[ファイル:Mery_ブックマークジャンプ_SS(2).png|frameless|254px|thumb|right|分割サブメニュー]]
[[ファイル:Mery_ブックマークジャンプ_SS(2).png|frameless|254px|thumb|right|分割サブメニュー]]
*ブックマークの件数が多いときはサブメニューに分割表示します。
* ブックマークの件数が多いときはサブメニューに分割表示します。
:初期値では 20 件超で分割サブメニューを表示する設定にしてありますが、モニターの高さに合わせて分割単位を変更することができます(設定変更サブメニューで変更可)。
: 初期値では 30 件超で分割サブメニューを表示する設定にしてありますが、モニターの高さに合わせて分割単位を変更することができます(設定変更サブメニューで変更可)。
<br>
※ スクリーンショット画像は開発中のサンプル画像です。<br>
「メニューの再表示位置を調整する」コマンドは実装していません。
<br clear=all><br>
<br clear=all><br>


*[[includeライブラリ]] を使用し、設定内容は外部ファイルに保存します(◆settingEnable 変数で設定。デフォルト: 有効)。<br>
* [[includeライブラリ]]」を使用し、設定内容は外部ファイルに保存します(変数 <code>settingEnable</code> で設定。デフォルト: 有効)。<br>
<div id="注1" class="warningbox">
<div id="注1" class="warningbox">
* あらかじめ [[includeライブラリ]] をインストールしてください。
* あらかじめ [[includeライブラリ]] をインストールしてください。
* 設定内容の保存場所は '''Mery\Macros\MacroSettings\<ブックマーク一覧ジャンプ>.json''' <br> または '''%AppData%\Mery\MacroSettings\<ジャンプ>.json''' です。<br> (※ <ブックマーク一覧ジャンプ> の部分はこのマクロのファイル名)
* 設定内容の保存場所は '''Mery\Macros\MacroSettings\<ブックマーク一覧ジャンプ>.json''' <br> または '''%AppData%\Mery\MacroSettings\<ブックマーク一覧ジャンプ>.json''' です。
: ※ <code><ブックマーク一覧ジャンプ></code> の部分はこのマクロのファイル名
</div>
</div>
: 「▼ 通常版 設定項目 ▼」以降の設定項目は『初期値』としてのみ利用され、ソースコード内の設定項目を直接書き換えする必要はありません。
: 「▼ 通常版 設定項目 ▼」以降の設定項目は『初期値』としてのみ利用され、ソースコード内の設定項目を直接書き換えする必要はありません。
: ※ ただし、settingEnable 変数を完全に無効にする場合は、ソースコード内で変更する必要があります。<br> settingEnable を無効にした場合は「通常版」と同じ状態になり、「設定変更」サブメニューが表示されなくなります。
: ※ ただし、settingEnable 変数を完全に無効にする場合は、ソースコード内で変更する必要があります。<br> settingEnable を無効にした場合は「通常版」とほぼ同じ状態になり、「設定変更」サブメニューが表示されなくなります。
 


; ソースコード


<source lang="javascript" style="height:80em; overflow:auto;">
<source lang="javascript" style="height:80em; overflow:auto;" highlight="23-41">
#title = "ブックマークジャンプ"
#title = "ブックマークジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#icon = "bookmark_list.ico"
#include "include/IO.js"
#include "include/IO.js"
#icon = "bookmark_list.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",243
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",243


481行目: 530行目:
  * ---------------------------------------------------------
  * ---------------------------------------------------------
  * 「ブックマーク一覧ジャンプ」
  * 「ブックマーク一覧ジャンプ」
  *  Orginal created by: Kuro, goat (2012/06/22 - 2012/09/24)
  *  https://www.haijin-boys.com/wiki/ブックマーク一覧ジャンプ
  *  Modified by:       sukemaru   (2018/08/08 - 2019/12/05)
*  Original created by: Kuro & goat (2012/06/22 - 2012/09/24)
  *   【include 版】                  (2019/04/15 - 2019/12/05)  
* ---------------------------------------------------------
  *  Modified         by: sukemaru   (2018/08/08 - 2020/06/24)
  * 【include版】    by: sukemaru    (2019/04/15 - 2020/06/24)
  * ---------------------------------------------------------
  * ---------------------------------------------------------
* 【include 版】
* ・「設定変更」サブメニューを表示
* ・ 設定内容を外部ファイル(JSON)に保存
* ・ ブックマーク件数が多いときはサブメニューに分割表示
*
*    設定ファイルの保存場所は
*      Mery\Macros\MacroSettings\<jsonName>.json
*    または
*      %AppData%\Mery\MacroSettings\<jsonName>.json
*    ※ <jsonName> の部分はこのマクロのファイル名(設定項目で変更可)
  */
  */


var start = new Date(); // 所要時間計測(開始)
var start = new Date(); // 所要時間計測(開始)
var setting = {};


var setting = {};
// ---------- ▼ 【include版】 初期設定項目 ▼ ---------- //
// ---------- ▼ 【include版】 初期設定項目 ▼ ---------- //


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


// ◆ JSON ファイルのベース名
// ◆ JSON ファイルのベース名
509行目: 550行目:


// 任意の名前に変更する場合はアンコメントして書き換える
// 任意の名前に変更する場合はアンコメントして書き換える
// jsonName = "ブックマーク一覧ジャンプ";
// jsonName = "ブックマークジャンプ";
 
 
// ■ 連番の桁埋め(右寄せ/空白埋め)用空白文字の定義
var blankChr = " "; // " " or "\u2002" or "\u3000" or "\u2007" or ...
 
  /* 半角数字の幅に等しい空白文字として
    MS UI Gothic では「2分アキ」 = EN SPACE: "\u2002"
    (MeiryoKe_UI Gothic は MS UI Gothic に同じ)
    Meiryo UI では「和字間隔」 = 全角空白: "\u3000"
    Segoe UI では「図形間隔」 = FIGURE SPACE: "\u2007"
    にすると具合がよさそうですが、ウエイトによって幅が変わるので... */
 
 
// ---------- ▼ 通常設定項目 ▼ ---------- //


// ---------- ▼ 通常版 設定項目 ▼ ---------- //
// 【include版】ではポップアップメニューから変更すること
// 【include版】ではポップアップメニューから変更すること
setting.blockSelectEnable = false;
setting.blockSelectEnable = false;
setting.keepInitialSelect = false;
setting.keepInitialSelect = false;
setting.endOfBookmarkLine = false;
setting.endOfBookmarkLine = false;
setting.autoLineModeEnable = false;
setting.autoLineModeEnable = false;
setting.lineColumnView = 0; // ( 0 論理行 / 1 表示行 )
setting.lineColumnView = false;
setting.extraMenuEnable = true;
setting.extraMenuEnable = true;
setting.menuPinEnable = true;
setting.menuPinEnable = true;
setting.menuScrollEnable = true; // スペースキーでスクロール
setting.menuScrollEnable = true;
setting.subMenuEnable = true; // 分割サブメニュー
setting.subMenuEnable = true;
setting.subMenuHeight = 20; // 初期値 = 20; (20 件* ずつに分割)
setting.subMenuStyle = 0;
setting.menuWidth = 55; // (30-100 程度 ※半角文字だけの行では×2)
setting.subMenuHeight = 30;
setting.toFullWidth = false; // [!"%'(),.:;@\[\]`a-z{|}]
setting.menuWidth = 55;
setting.menuPosMouse = true; // ( true マウス位置 / false カーソル位置 )
setting.toWideWidth = 0;
setting.menuPosMouse = true;


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




// menuWidth = ( menuWidth < 30 )  ? 25
/* ▼ 【include版】用の追加コード ▼ */  
//          : ( menuWidth > 100 ) ? 105
//                                : menuWidth;


// ソースコードの「設定項目」内の初期値を保存する
// ソースコードの「設定項目」内の初期値を保存する
542行目: 594行目:
   setting  = IO.Deserialize( setting, jsonName );
   setting  = IO.Deserialize( setting, jsonName );
   // 通常版の設定変数に再代入
   // 通常版の設定変数に再代入
   var settingEnable = setting.settingEnable;
   var settingEnable     = setting.settingEnable;
   var blockSelectEnable = setting.blockSelectEnable;
   var blockSelectEnable  = setting.blockSelectEnable;
   var keepInitialSelect = setting.keepInitialSelect;
   var keepInitialSelect  = setting.keepInitialSelect;
   var endOfBookmarkLine = setting.endOfBookmarkLine;
   var endOfBookmarkLine  = setting.endOfBookmarkLine;
   var extraMenuEnable = setting.extraMenuEnable;
   var extraMenuEnable   = setting.extraMenuEnable;
   var menuPinEnable = setting.menuPinEnable;
   var menuPinEnable     = setting.menuPinEnable;
   var menuScrollEnable = setting.menuScrollEnable;
   var menuScrollEnable   = setting.menuScrollEnable;
   var autoLineModeEnable = setting.autoLineModeEnable;
   var autoLineModeEnable = setting.autoLineModeEnable;
   var lineColumnView = setting.lineColumnView;
   var lineColumnView     = setting.lineColumnView;
   var subMenuEnable = setting.subMenuEnable;
   var subMenuEnable     = setting.subMenuEnable;
   var subMenuHeight = setting.subMenuHeight;
  var subMenuStyle      = setting.subMenuStyle;
   var menuWidth = setting.menuWidth;
   var subMenuHeight     = setting.subMenuHeight;
   var toFullWidth = setting.toFullWidth;
   var menuWidth         = setting.menuWidth;
   var menuPosMouse = setting.menuPosMouse;
   var toWideWidth        = setting.toWideWidth;
   var menuPosMouse       = setting.menuPosMouse;
  var mouseDllEnable    = setting.mouseDllEnable;
}
/* ▲ 【include版】用のコード ▲ */
 
// 連番の桁埋め(右寄せ/空白埋め)用
var b1 = ( ! blankChr || ( "" + blankChr ).length > 1 )
      ? " " : blankChr;
/**
* Object.prototype.PadSpace( len, chr )
* Object オブジェクトに拡張メソッドを追加(グローバル)
* 数値/文字列の左側を chr で桁埋めした文字列をかえす
*/
Object.prototype.PadSpace = function(len, chr) {
  var dgt = String(this);
  len = Number(len) || dgt.length;
  chr = chr ? chr.toString() : b1;
  if (len < 0 || len < dgt.length || chr.length !== 1) return dgt;
  for (var i = 0; i < len; i++) chr += chr;
  return (chr + dgt).slice(- len);
};
 
// カーソルと選択範囲の位置を保存
var d = editor.ActiveDocument,  s = d.selection;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var l_ay  = s.GetActivePointY( mePosLogical );
var v_ay  = s.GetActivePointY( mePosView );
var sx = ScrollX,  sy = ScrollY;
// ブックマーク行の変数
var bmArray = [];
var bmY, bmStr, vy, ly, y;
// アクティブ行がブックマークされているか
var flag = 0,  isBookmarked = 0;
 
// ブックマーク行を検索
Redraw = false;
// 先頭行がブックマークされているか
s.SetActivePoint( mePosLogical, 1, 2 );
if ( s.PreviousBookmark() ) {
  ly = s.GetActivePointY( mePosLogical );
  vy = s.GetActivePointY( mePosView );
  if ( ly === l_ay ) { flag = 1;  isBookmarked = 1; }
  bmArray.push( { LY: ly,  VY: vy,  flag: flag } );
}
// 2行目以降のブックマークを探す
s.SetActivePos( 0 );
while ( s.NextBookmark() ) {
  ly = s.GetActivePointY( mePosLogical );
  vy = s.GetActivePointY( mePosView );
  if ( ly === l_ay ) { flag = 1;  isBookmarked = 1; }
  else { flag = 0; }
  bmArray.push( { LY: ly,  VY: vy,  flag: flag } );
}
}
// ブックマークの件数
var bmCount = bmArray.length;
// カーソル位置と選択範囲を復帰
s.SetActivePos( act );  s.SetAnchorPos( anc );
ScrollX = sx;  ScrollY = sy;
Redraw = true;
// ---------- ▼ ループ開始位置 ▼ ---------- //


do {
do {
   if ( y ) { start = new Date(); } // ループしたときはタイマーをリセット
  // ループしたときはタイマーをリセット
   if ( y ) { start = new Date(); }


   // Mery.ini から「行の表示方法」を取得する
   // Mery.ini から「行の表示方法」を取得する
565行目: 679行目:
     lineColumnView = GetIniOptionNum( "LineColumnView" );
     lineColumnView = GetIniOptionNum( "LineColumnView" );
   }
   }
  // 表示行/論理行 の定数
   var ay = lineColumnView ? v_ay : l_ay;
   var posMode  = lineColumnView ? mePosView : mePosLogical;
  var lineMode = lineColumnView ? meGetLineView : 0;
   // 全体の行数
   // 全体の行数
  var d = editor.ActiveDocument;
   var lines = d.GetLines( lineColumnView ? meGetLineView : 0 );
   var lines = d.GetLines( lineMode );
   // ブックマーク行の文字列を取得する
  var linesWidth = lines.toString().length;
   if ( bmCount ) {
   // カーソルと選択範囲の位置を保存
    for ( var i = 0; i < bmCount; i ++ ) {
   var s = d.selection;
      bmY = lineColumnView ? bmArray[i].VY : bmArray[i].LY;
  var act = s.GetActivePos(),  anc = s.GetAnchorPos();
      bmStr = d.GetLine( bmY, lineColumnView ? meGetLineView : 0 );
  var aY = s.GetActivePointY( posMode );
      bmArray[i].id = bmY;
  var sX = ScrollX, sY = ScrollY;
      bmArray[i].str = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
  // ブックマーク行の変数
    }
  var bmArray = [],  flag = 0,  isBookmarked = 0;
  var bmY,  bmStr;
 
  // ブックマーク行を検索
  Redraw = false;
  // 先頭行がブックマークされているか
  s.SetActivePoint( mePosLogical, 1, 2 );
  if ( s.PreviousBookmark() ) {
    bmY = s.GetActivePointY( posMode );
    bmStr = d.GetLine( bmY, lineMode );
    if ( bmY == aY ) { flag = 1; isBookmarked = 1; }
    bmArray.push( [ MenuKey( bmStr, bmY ), bmY, flag ] );
   }
   }
   // 2行目以降のブックマークを探す
   var numWidth = ( ( menuPinEnable || ! bmCount ) ? lines : bmY )
  s.SetActivePos( 0 );
                .toString().length;
  while ( s.NextBookmark() ) {
    bmY = s.GetActivePointY( posMode );
    bmStr = d.GetLine( bmY, lineMode );
    if ( bmY == aY ) { flag = 1;  isBookmarked = 1; }
    else { flag = 0; }
    bmArray.push( [ MenuKey( bmStr, bmY ), bmY, flag ] );
  }
  // ブックマークの件数
  var bmCount = bmArray.length;
 
  // カーソル位置と選択範囲を復帰
  s.SetActivePos( act );  s.SetAnchorPos( anc );
  ScrollX = sX;  ScrollY = sY;
  Redraw = true;
 
  // ステータスラベル
  var status1 = bmCount
              ? " ブックマーク: " + bmCount + " 件 /"
              : " ブックマークがありません。";
  var status2 = " 全体の行数: "
              + lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
              + ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );


   // ポップアップメニューの準備
   // ポップアップメニューの準備
   var bmMenu = CreatePopupMenu();
   var bmMenu = CreatePopupMenu();


   // 「ブックマーク一覧」ポップアップメニュー
   // ステータスラベル
   // または「ブックマークがありません」ポップアップメニュー
   var status1 = ( bmCount )
   BookmarkMenu( bmMenu, bmArray, aY );
  ? " ブックマーク: "
    + bmCount.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
    + " 件 "
   : " ブックマークがありません。 ";
  var status2 = ( bmCount ? "/ " : "" )
  + "全体の行数: "
  + lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
  + ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );


   // ステータスバーとポップアップメニューを表示
   // アクティブ行のチェックマークフラグ (meMenuChecked = 1)
  Status = status1 + status2
   var Check = function( num ) { return ( num === ay ) *1; }
        + TimerElapsed( new Date(), start );
   var y = bmMenu.Track( menuPosMouse );
 
  /* 【include版】の設定変更サブメニュー項目を選択した場合 */
  if ( y >= 10000000 && y <= 10000018 ) {
    SettingsChange( y );
  }
// 設定変更した場合はメニューを再表示する
} while ( ! menuPosMouse && y >= 10000000 && y <= 10000015 );
 
// ブックマークを設定/解除
if ( y == 20000000 ) {
  editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}
 
// ジャンプ
else if ( y && y < 10000000 ) {
  Redraw = false;
  s.SetActivePoint( posMode, 1, y );
 
  // アクティブ行へのジャンプではスクロール位置をリセット
  if ( y == aY ) { ScrollY = aY; }
  // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
  if ( blockSelectEnable && act !== anc ) {
    var jumpDown = ( aY < y );
    // もとの選択範囲の文字列を含んだままにする
    if ( keepInitialSelect ) {
      var tp = Math.min( anc, act );
      var bp = Math.max( anc, act );
      s.SetAnchorPos( jumpDown ? tp : bp );
    }
    // または、もとの "キャレット位置" を範囲選択の基点にする
    else { s.SetAnchorPos( act ); }
    // 下の行へジャンプしたとき、ジャンプ先の行全体を選択範囲に含める
    if ( jumpDown && endOfBookmarkLine ) {
      s.EndOfLine( true, mePosLogical );
      ScrollX = 1; // 水平スクロールを左端にリセット
    }
  }
  ScrollY = ( ScrollY == sY )
          ? sY : s.GetActivePointY( mePosView );
  Redraw = true;
}
 
// ---------- ▼ 関数 ▼ ---------- //


/**
* 関数 BookmarkMenu( objMenu, objArray )
* 「ブックマーク一覧」ポップアップメニュー
* または「ブックマークがありません」ポップアップメニュー
*
* ※各変数はグローバルスコープのものを利用する
*/
function BookmarkMenu( bmMenu, bmArray ) {
  // アクティブ行のチェックマークフラグ (meMenuChecked = 1)
  var Check = function( num ) { return ( num == aY ) *1; }
   // ピン止めアイテム
   // ピン止めアイテム
   var bmPin = MenuIndent( aY, linesWidth )
   var bmPin     = ay.PadSpace( numWidth ) + ": "
          + ":  ブックマークを設定/解除 (&B)";
                + "ブックマークを設定/解除 (&B)";
   var countPin = MenuIndent()
   var countPin = "".PadSpace( numWidth )
              + " ▼ " + status1.slice( 0, -1 ) + " ▼";
                + " ▼ " + status1 + " ▼";
   var cancelPin = MenuIndent()
   var cancelPin = "".PadSpace( numWidth )
              + "  キャンセル\t& ";
                + " キャンセル\t& ";
   var topPin = MenuIndent( 1, linesWidth )
   var topPin   = ( 1 ).PadSpace( numWidth ) + ": "
            + ":  ** 先頭行へジャンプ (&T) **";
                + "** 先頭行へジャンプ (&T) **";
   var endPin = MenuIndent( lines, linesWidth )
   var endPin   = lines.PadSpace( numWidth ) + ": "
            + ":  ** 最終行へジャンプ (&E) **";
                + "** 最終行へジャンプ (&E) **";
   var actPin = MenuIndent( aY, linesWidth )
   var actPin   = ay.PadSpace( numWidth ) + ": "
            + ":    行頭へジャンプ (&A)";
                + "** 行頭へジャンプ (&A) **";


   // メニューの最上部に「設定/解除」をピン止め
   // メニューの最上部に「設定/解除」をピン止め
   if ( bmCount || extraMenuEnable ) {
   if ( bmCount || extraMenuEnable ) {
     bmMenu.Add( bmPin, 20000000, isBookmarked );
     bmMenu.Add( bmPin, 20000000, isBookmarked );
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
     bmMenu.Add( "----", 0, meMenuSeparator );
     bmMenu.Add( "----", 0, meMenuSeparator );


     /* 【include版】の設定変更サブメニュー */  
     /* 【include版】の設定変更サブメニュー */  
     if ( initialSettings.settingEnable ) {
     if ( initialSettings.settingEnable ) {
       SettingsMenu( bmMenu );
       bmMenu.AddPopup( "".PadSpace( numWidth )
                      + " 設定を変更する (&S)"
                    , SettingsMenu( setting ) );
      bmMenu.Add( "----", 0, meMenuSeparator );
     }
     }
   }
   }
708行目: 743行目:
   // 「ブックマーク一覧」ポップアップメニュー
   // 「ブックマーク一覧」ポップアップメニュー
   if ( bmCount ) {
   if ( bmCount ) {
  // メニュー上部のピン止めアイテム
    bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
    bmMenu.Add( "----", 0, meMenuSeparator );
     bmMenu.Add( "----", 0, meMenuSeparator );
     bmMenu.Add( "----", 0, meMenuSeparator );
     // メニュー上部のピン止めアイテム
     // メニュー上部のピン止めアイテム
     if ( menuPinEnable && ( bmArray[0][1] > 1
     if ( menuPinEnable
        || ! isBookmarked && aY > 1 && aY < lines ) ) {
    && ( bmArray[0].id > 1 || ! isBookmarked && ay > 1 && ay < lines ) ) {
       if ( bmArray[0][1] > 1 ) {
       if ( bmArray[0].id > 1 ) {
         bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
         bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
       }
       }
       if ( ! isBookmarked && aY > 1 && aY < lines ) {
       if ( ! isBookmarked && ay > 1 && ay < lines ) {
         bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
         bmMenu.Add( actPin, ay, meMenuChecked ); // 「行頭へジャンプ」
       }
       }
       if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ][1] !== lines ) {
       if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ].id !== lines ) {
         bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
         bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
       }
       }
729行目: 761行目:
     // 「分割サブメニュー」をピン止め
     // 「分割サブメニュー」をピン止め
     if ( subMenuEnable && bmCount > subMenuHeight ) {
     if ( subMenuEnable && bmCount > subMenuHeight ) {
       var subMenu = DevidedSubMenuBM( bmMenu, bmArray );
       DevidedMenu( bmMenu, bmArray, bmCount, numWidth, subMenuStyle, subMenuHeight, b1 );
     }
     }


     // ブックマーク一覧
     // ブックマーク一覧
     bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
     bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
     for ( var i = 0; i < bmCount; i ++ ) {
     for ( var i = 0, bm, num; i < bmCount; i ++ ) {
       if ( i % 10 == 0 && i > 0 ) {
       if ( i % 10 === 0 && i > 0 ) {
         bmMenu.Add( "----", 0, meMenuSeparator ); // 10行ごとにセパレータ
         bmMenu.Add( "----", 0, meMenuSeparator ); // 10行ごとにセパレータ
         if ( menuScrollEnable && i % subMenuHeight == 0 ) {
         if ( menuScrollEnable && i % subMenuHeight === 0 ) {
           bmMenu.Add( cancelPin, 0 ); // 20行* ごとに「キャンセル」
           bmMenu.Add( cancelPin, 0 ); // 30行* ごとに「キャンセル」
           bmMenu.Add( "----", 0, meMenuSeparator );
           bmMenu.Add( "----", 0, meMenuSeparator );
         }
         }
       }
       }
       // ブックマーク行をポップアップメニューに追加
       // ブックマーク行をポップアップメニューに追加
       bmMenu.Add( bmArray[i][0], bmArray[i][1], Check( bmArray[i][1] ) );
      bm  = bmArray[i];
      num = bm.id.PadSpace( numWidth ).replace( /\d$/, "&$&: " );
       bmMenu.Add( num + bm.str, bm.id, Check( bm.id ) );
     }
     }


     // メニュー下部のピン止めアイテム
     // メニュー下部のピン止めアイテム
     if ( menuPinEnable && bmArray[ bmCount -1 ][1] !== lines ) {
     if ( menuPinEnable && bmArray[ bmCount -1 ].id !== lines ) {
       bmMenu.Add( "----", 0, meMenuSeparator );
       bmMenu.Add( "----", 0, meMenuSeparator );
       bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
       bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
753行目: 787行目:
     if ( menuScrollEnable && bmCount > subMenuHeight ) {
     if ( menuScrollEnable && bmCount > subMenuHeight ) {
       bmMenu.Add( "----", 0, meMenuSeparator );
       bmMenu.Add( "----", 0, meMenuSeparator );
       bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
       bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
     }
     }
   }
   }
759行目: 793行目:
   // 「ブックマークがありません」ポップアップメニュー
   // 「ブックマークがありません」ポップアップメニュー
   else if ( extraMenuEnable ) {
   else if ( extraMenuEnable ) {
    bmMenu.Add( "----", 0, meMenuSeparator );
     // 「ブックマークがありません」
     // ステータスラベルをピン止め
     bmMenu.Add( "※ " + status1 + " ※", 0, meMenuGrayed );
     bmMenu.Add( "※ " + status1 + " \t& ", 0 ); // 「ブックマークがありません」
     if ( ! menuPinEnable ) {
     if ( ! menuPinEnable ) {
       bmMenu.Add( " " + status2, 0 ); // 全体の行数
       bmMenu.Add( " " + status2, 0 ); // 全体の行数
     }
     }
     // ピン止めアイテム
     // ピン止めアイテム
770行目: 803行目:
         bmMenu.Add( "----", 0, meMenuSeparator );
         bmMenu.Add( "----", 0, meMenuSeparator );
         bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
         bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
         if ( aY > 1 && aY < lines ) {
         if ( ay > 1 && ay < lines ) {
           bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
           bmMenu.Add( actPin, ay, meMenuChecked ); // 「行頭へジャンプ」
         }
         }
         bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
         bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
       } else {
       }
         bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
      else {
         bmMenu.Add( actPin, ay, meMenuChecked ); // 「行頭へジャンプ」
       }
       }
     }
     }
   }
   }
  // ステータスとポップアップメニューを表示
  Status = status1 + status2
        + TimerElapsed( new Date(), start );
  var y = bmMenu.Track( menuPosMouse );
  /* 【include版】の設定変更サブメニュー項目を選択した場合 */
  if ( y >= 10000000 && y < 20000000 ) {
    SettingsChange( y );
  }
// 設定変更した場合はメニューを再表示する
} while ( y >= 10000000 && y < 10000100 && ! menuPosMouse  );
// ---------- ▲ ループ ここまで ▲ ---------- //
// ブックマークを設定/解除
if ( y === 20000000 ) {
  editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}
}


/**
// ジャンプ
* 関数 MenuIndent( str )
else if ( y && y < 10000000 ) {
* メニューラベルの字下げ
  s.SetActivePoint( lineColumnView ? mePosView : mePosLogical, 1, y );
*/
  var yy = s.GetActivePointY( mePosView );
function MenuIndent( str ) {
 
   str = str || "";
  // アクティブ行へのジャンプではスクロール位置をリセット
  var appendix = /^&\d/.test( str ) ? 1 : 0;
  if ( y === ay ) { ScrollY = yy }
  return ( "          " + str ).slice( - linesWidth - appendix );
 
   // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
  if ( blockSelectEnable && act !== anc ) {
    var jumpDown = ( ay < y );
    // もとの選択範囲の文字列を含んだままにする
    if ( keepInitialSelect ) {
      var tp = Math.min( anc, act );
      var bp = Math.max( anc, act );
      s.SetAnchorPos( jumpDown ? tp : bp );
    }
    // または、もとの "キャレット位置" を範囲選択の基点にする
    else { s.SetAnchorPos( act ); }
    // 下の行へジャンプしたとき、ジャンプ先の行全体を選択範囲に含める
    if ( jumpDown && endOfBookmarkLine ) {
      s.EndOfLine( true, mePosLogical ); // ※ 表示行にも対応させるべきか?
      ScrollX = 1; // 水平スクロールを左端にリセット
    }
  }
  ScrollY = ( ScrollY === sy ) ? sy : yy;
}
}
// ---------- ▼ 関数 ▼ ---------- //


/**
/**
  * 関数 MenuKey( str, num )
  * 関数 MenuKey( str, maxStrLength, toWideWidth, blankChr )
  * ポップアップメニューに表示するラベルを生成する
  * ポップアップメニューに表示するラベルを生成する
  *  
  *  
  * ・行頭空白を除去、空白文字を圧縮
  * ・行頭空白を除去、空白文字を圧縮
  * ・「&」 を補完
  * ・削られてしまう 「&」 を補完
  * ・「¥」(U+005C) を 「∖」(U+2216) に置換:   または 「╲」(U+2572), 「﹨」(U+FE68)
  * ・「¥」(\u005C) を 「∖」(\u2216) に置換:     または 「╲」(\u2572), 「﹨」(\uFE68)
  * ・ゼロ幅や特殊な空白文字を豆腐に置換: → 「▯」(U+25AF) または 「⊠」(U+22A0)
  * ・ゼロ幅や特殊な空白文字を豆腐に置換:   「⊠」(\u22A0) または 「▯」(\u25AF)
  * ・判別しづらい半角記号を全角に置換: !"%'(),.:;@[]`{|}
  * ・判別しづらい半角記号を全角に置換:     !"%'(),.:;@[]`{|}
  *    + 「a-z」 を全角に置換
  *    + 「a-z」 を全角に置換
  *  または半角記号の前後にスキマをつける: HAIR SPACE 「 」(U+200A)
  *  または半角記号の前後にスキマをつける: HAIR SPACE 「 」(\u200A)
  * ・文字数を切り詰め
  * ・文字数を切り詰め
* ・行番号を空白でケタ埋め: EN SPACE 「 」(U+2002)
  */
  */
function MenuKey( str, num ) {
function MenuKey( str, menuWidth, toWideWidth, b1 ) {
   var keyWidth = /^[\s ]*[\s!-~∖▯⊠ ]+$/.test( str ) ? menuWidth * 2 : menuWidth;
  // HAIR SPACE( ),「∖」「⊠」「▯」
   var keyWidth = ( /^[\s ]*[\s!-~\u200A\u2216\u22A0\u25AF]+$/.test( str ) )
              ? Math.floor( menuWidth *1.2 ) : menuWidth;
   var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
   var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
   var regBlank = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g
   var key = str ? ( regBlankLine.test( str ) ? "( 空白行 )" : str )
  var menuKey = ( str ) ? regBlankLine.test( str ) ? "( 空白行 )" : str
                : "( 空行 )";
                        : "( 空行 )";
  var regBlankChar = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g;
   menuKey = menuKey.replace( /^[\t  ]+/, "" )
   key = key.replace( /^[\s ]+/, "" )
                  .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
          .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " \u203A " ) //「 › 」
                  .slice( 0, keyWidth + 1 )
          .slice( 0, keyWidth + 1 )
                  .replace( /[&]/g, "&&" )
          .replace( /&/g, "&&" )
                  .replace( /[\\]/g, "" )
          .replace( /\\/g, "\u2216" )         //「∖」
                  .replace( regBlank, "" );
          .replace( regBlankChar, "\u25AF" ); //「▯」
   if ( toFullWidth ) {
  // 半角英小文字と ascii記号を全角化
     menuKey = menuKey.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
   if ( toWideWidth === 2 ) {
      function( tmp ) {
     key = key.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
      } );
    } );
   }
   }
   else {
   // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (\u200A) を付加
    // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (U+200A) を付加
  else if ( toWideWidth === 1 ) {
     menuKey = menuKey.replace( /[!-%'-.:-@\[-`{-~fijl¥⊠▯]|&&/g, "$&" )
     key = key.replace( /[!-%'-.:-@\[-`{-~fijl\u00A5\u22A0\u25AF]|&&/g,
                    .replace( /\u200A+/g, "" )
              "\u200A$&\u200A" ) //「¥」「⊠」「▯」
                    .replace( /\u2002\u200A/g, "" );
            .replace( /\u200A+/g, "\u200A" ) // HAIR SPACE
     keyWidth = keyWidth
            .replace( RegExp( b1 + "\u200A", "g" ), b1 );
            + ( menuKey.match( /[\u200A›↲]|&&/g ) || "" ).length;
    // HAIR SPACE,「›」
     keyWidth += ( key.match( /[\u200A\u203A]|&&/g ) || "" ).length;
   }
   }
   menuKey = ( menuKey.length > keyWidth )
   key = ( key.length > keyWidth )
          ? menuKey.slice( 0, keyWidth ) + " ..."
      ? key.slice( 0, keyWidth ) + " ..." : key;
          : menuKey;
   return key;
  num = MenuIndent( "&" + num ) + ": ";
   return num + menuKey;
}
}


855行目: 929行目:
   // Mery.ini を探す
   // Mery.ini を探す
   var meryPath = editor.FullName;
   var meryPath = editor.FullName;
  var mery    = Fso.GetBaseName( meryPath );
   var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
   var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
   if ( ! Fso.FileExists( iniPath ) ) {
   if ( ! Fso.FileExists( iniPath ) ) {
     var WshShell = new ActiveXObject( "WScript.Shell" );
     var mery = Fso.GetBaseName( meryPath );
    iniPath = WshShell.ExpandEnvironmentStrings( "%APPDATA%" )
    iniPath = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
             + "\\Mery\\" + mery + ".ini";
             + "\\Mery\\" + mery + ".ini";
   }
   }
869行目: 943行目:
   return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
   return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
}
}
// ---------- ▼ 【include版】 関数 ▼ ---------- //


/**
/**
  * 関数 DevidedSubMenuBM( objPopupMenu, items )
  * 関数 DevidedMenu( objPopupMenu, itemsArray, itemsCount, numWidth, subMenuStyle, subMenuHeight, blankChr )
  * サブメニュー「※ 20* 件ずつ表示 ※  ▶」/「1 - 20* 件目  ▶」に
  * サブメニュー「※ 20* 件ずつ表示 ※  ▶」/「 1 - 20* 件目  ▶」に
  * 配列の「アイテム」を分割表示する
  * 配列の「アイテム」を分割表示する
  * ※「20*」の部分の数値は設定用変数 subMenuHeight で指定
  * ※「 1 - 20 件目  ▶」の先頭にチェックマーク「*」をつけるために
*  for() ループを2回まわす
  */
  */
function DevidedSubMenuBM( objPopupMenu, items ) {
function DevidedMenu( objPopupMenu, bmArray, bmCount, numWidth, subMenuStyle, subMenuHeight, b1 ) {  
   var len      = items.length;
   b1 = ( b1.length === 1 ) ? b1 : " ";
   var lenWidth = len.toString().length;
   var devidedSubMenu = CreatePopupMenu();
   var smRow    = Math.ceil( len / subMenuHeight );
   var indent = "".PadSpace( numWidth, b1 );
  var smSq    = subMenuHeight * subMenuHeight;
   var smArray = [];
   var smArray = []; // SubMenu Array
   var tickedId;
   var smLabelArray = []; // SubMenu-Label Array
  var smId,  _from,  _to,  tick,  ticked;


  var subMenu  = CreatePopupMenu();
   if ( subMenuStyle ) {
  var popupMenu = ( subMenuEnable == 1 )
                ? subMenu : objPopupMenu;
   if ( subMenuEnable == 1 ) {
     // 「※ 20* 件ずつ表示 ※  ▶」をピン止め
     // 「※ 20* 件ずつ表示 ※  ▶」をピン止め
     objPopupMenu.AddPopup( MenuIndent() + " ※   "
     objPopupMenu.AddPopup( indent
                        + subMenuHeight + " 件ずつに分割して表示 (&D)  ※"
    + " ※   " + subMenuHeight + " 件ずつに分割して表示 (&D)  ※"
                        , subMenu );
    , devidedSubMenu );
     objPopupMenu.Add( "", 0, meMenuSeparator );
     objPopupMenu.Add( "", 0, meMenuSeparator );
   }
   }


   // サブメニューと配列のアイテムをポップアップメニューに追加していく
   // 配列 bmArray のアイテムをサブメニューに追加していく
   for ( var i = 0; i < len; i ++ ) {
  bmArrayLoop:
    // セパレータと「キャンセル」
   for ( var i = 0, j = 1, k = subMenuHeight, subMenu, line, num;
     if ( i % subMenuHeight == 0 ) {
  i < bmCount; i ++, j ++, k ++ ) {
      if ( smRow > 10 && i != 0 && i % ( subMenuHeight * 10 ) == 0 ) {
     if ( i % subMenuHeight === 0 ) {
        popupMenu.Add( "", 0, meMenuSeparator );
       // smArray に「_from - _to 件目  ▶」用のサブメニューを生成する
        if ( len > smSq && i % smSq == 0 ) {
       subMenu = CreatePopupMenu();
          popupMenu.Add( MenuIndent() + "  キャンセル\t& ", 0 );
       smArray.push( {
          popupMenu.Add( "", 0, meMenuSeparator );
        menu: subMenu,
        }
        from: j,
      }
        to: ( k < bmCount ) ? k : bmCount
 
       } );
       // 配列 smArray 内にメニュー項目「_from - _to 件目  ▶」を生成
       smArray.push( CreatePopupMenu() );
       // 「_from - _to 件目  ▶」メニューの index
      smId  = smArray.length - 1;
      //  _from と _to の値
      _from = smId * subMenuHeight + 1;
      _to  = Math.min( smArray.length * subMenuHeight, len );
       // 「_from - _to 件目」メニューラベルを別途の配列 smLabelArray に
      smLabelArray.push( ( "       &" + _from ).slice( - lenWidth - 1 )
                      + " - "
                      + ( "       " + _to ).slice( - lenWidth )
                      + " 件目" );
     }
     }


     // 「アイテム」の配列から「_from - _to 件目」サブメニュー配下に
     // bmArray のアイテムをサブメニュー配下に追加する
     // ※ smArray[smId] は CreatePopupMenu オブジェクト
     // ※ なぜか smArray[smArray.length -1].menu ではなく subMenu への Add() でよい
     smArray[ smId ].Add( items[i][0], items[i][1], items[i][2] );
     line  = bmArray[i];
     // アクティブ行のフラグのついた行
    num = line.id.PadSpace( numWidth, b1 ).replace( /\d$/, "&$&: " );
     if ( items[i][2] ) { ticked = smId; }
    subMenu.Add( num + line.str, line.id, line.flag );
     // アクティブ行のチェックマークフラグのついた行
     if ( line.flag === 1 ) { tickedId = smArray.length - 1; }


     // 10 行ごとにセパレータ、さいごに「キャセル」行
     // 10 件ごとにセパレータ、height ごとに「キャセル」行
     if ( ( i + 1 ) % 10 == 0 || i == len - 1) {
     if ( j % 10 === 0 || j === bmCount) {
       smArray[ smId ].Add( "", 0, meMenuSeparator );
       subMenu.Add( "", 0, meMenuSeparator );
       if ( ( i + 1 ) % subMenuHeight == 0 || i == len - 1 ) {
       if ( j % subMenuHeight === 0 || j === bmCount ) {
         smArray[ smId ].Add( MenuIndent() + "  キャンセル\t& ", 0 );
         subMenu.Add( indent + " キャンセル\t& ", 0 );
       }
       }
     }
     }
  } // end: for ()
  // 「_from - _to 件目」メニュー項目をメニューに追加
  for ( var i = 0; i < smArray.length; i ++ ) {
    // ※ AddPopup には meMenuChecked を付けられないので "*" 記号で代替
    tick = ( i == ticked ) ? "* " : "  ";
    popupMenu.AddPopup( tick + smLabelArray[i], smArray[i] );
   }
   }
  // 「_from - _to 件目」のさいごに「キャセル」を追加
  subMenu.Add( "", 0, meMenuSeparator );
  subMenu.Add( "       ".slice( - lenWidth ) + "キャンセル\t& ", 0 );


   return subMenu;
   // 「_from - _to 件目  ▶」メニュー項目を親メニュー内に追加
}
  var popupMenu = subMenuStyle ? devidedSubMenu : objPopupMenu;
  var bmWidth  = bmCount.toString().length;
  var smIndent  = subMenuStyle ?  "" : indent;


  smArrayLoop:
  for ( var i = 0, smCount = smArray.length, tick, smLabel;
  i < smCount; i ++ ) {
    // ※ AddPopup に meMenuChecked は付けられないので文字「*」で代替
    tick = ( i === tickedId ) ? "* " : b1 + " ";
    smLabel = smArray[i].from.PadSpace( bmWidth, b1 ).replace( /\d/, "&$&" )
            + " - "
            + smArray[i].to.PadSpace( bmWidth, b1 ) + " 件目:";
    // ※ smArray[i].menu は PopupMenu オブジェクト
    popupMenu.AddPopup( smIndent + tick + smLabel, smArray[i].menu );


// ---------- ▼ 【include版】 関数 ▼ ---------- //
    // セパレータと「キャセル」行
    if ( ( i % subMenuHeight === 0 && i !== 0 ) || i === smCount - 1 ) {
      popupMenu.Add( "", 0, meMenuSeparator );
      if ( subMenuStyle ) {
        popupMenu.Add( " キャンセル\t& ", 0 );
      }
    }
    if ( i % 10 === 0 && i !== 0 ) {
      popupMenu.Add( "", 0, meMenuSeparator );
    }
  }
}


/**
/**
  * 関数 SettingsMenu( objPopupMenu )
  * 関数 SettingsMenu( objSettinds )
  * ポップアップメニューに「設定変更」サブメニューを表示する
  * ポップアップメニューに「設定変更」サブメニューを表示する
* 引数: メインスコープのポップアップメニューオブジェクト
  */
  */
function SettingsMenu( objMenu ) {
function SettingsMenu( setting ) {
   var subMenu = CreatePopupMenu();
   var ss = setting;
  var setMenu = CreatePopupMenu();
   // メニューのオプションフラグ
   // メニューのオプションフラグ
   var grayFlag = ! settingEnable ? meMenuGrayed : 0;
  // ※ meMenuChecked の数値は 1 なので hogeEnable *1 で代用できる
   var grayFlag1 = ( ! blockSelectEnable || ! settingEnable )
  // ※ meMenuGrayed の数値は 2 なので hogeEnable *2 で代用できる
                ?  meMenuGrayed : 0;
   var grayFlag = ! ss.settingEnable ? meMenuGrayed : 0;
   var keepInitialSelectFlag = ( keepInitialSelect && blockSelectEnable )
   var blockSelectGrayFlag = ! ss.blockSelectEnable *2 || grayFlag;
                            ? meMenuChecked : 0;
   var keepInitialSelectFlag = blockSelectGrayFlag
   var endOfBookmarkLineFlag = ( endOfBookmarkLine && blockSelectEnable )
  + ( ss.keepInitialSelect && ss.blockSelectEnable ) *1;
                            ? meMenuChecked : 0;
   var endOfBookmarkLineFlag = blockSelectGrayFlag
   var grayFlag2 = ( autoLineModeEnable || ! settingEnable )
  + ( ss.endOfBookmarkLine && ss.blockSelectEnable ) *1;
                ?  meMenuGrayed : 0;
   var autoLineModeGrayFlag = ss.autoLineModeEnable *2 || grayFlag;
   var maxHeightFlag = ( ! settingEnable || ! subMenuEnable || subMenuHeight >= 100 )
   var subMenuFlag = ! ss.subMenuEnable *2 || grayFlag;
                          ? meMenuGrayed : 0;
  var maxHeightFlag = ( ss.subMenuHeight >= 100 ) *2 || subMenuFlag;
   var minHeightFlag = ( ! settingEnable || ! subMenuEnable || subMenuHeight < 20 )
   var minHeightFlag = ( ss.subMenuHeight < 20 ) *2 || subMenuFlag;
                          ? meMenuGrayed : 0;
   var maxWidthFlag = ( ss.menuWidth > 100 ) *2 || grayFlag;
   var maxWidthFlag = menuWidth > 100 ? meMenuGrayed : 0;
   var minWidthFlag = ( ss.menuWidth < 30 ) *2 || grayFlag;
   var minWidthFlag = menuWidth < 30 ? meMenuGrayed : 0;
 
  // 「設定変更」サブメニューのアイテム
  objMenu.AddPopup( MenuIndent() + "  設定を変更する (&S)", subMenu );
  objMenu.Add( "----", 0, meMenuSeparator );


   subMenu.Add( "  ジャンプ先の行まで 範囲選択する (&B)",
   // 「設定変更」サブメニューのアイテム
              10000001, blockSelectEnable + grayFlag );
  setMenu.Add( "  ジャンプ先の行まで 範囲選択する (&B)"
   subMenu.Add( " もとの選択範囲を ジャンプ後の範囲選択に含める (&K)",
            , 10000001, ss.blockSelectEnable + grayFlag );
              10000002, keepInitialSelectFlag + grayFlag1 );
   setMenu.Add( "  もとの選択範囲を ジャンプ後の範囲選択に含める (&K)"
   subMenu.Add( " 下の行にジャンプしたときに 行全体を選択 (&E)",
            , 10000002, keepInitialSelectFlag );
              10000003, endOfBookmarkLineFlag + grayFlag1 );
   setMenu.Add( "  下の行にジャンプしたときに 行全体を選択 (&E)"
   subMenu.Add( "----", 0, meMenuSeparator );
            , 10000003, endOfBookmarkLineFlag );
   subMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "----", 0, meMenuSeparator );
   subMenu.Add( "  ブックマークがなくても メニューを表示する (&N)",
   setMenu.Add( "----", 0, meMenuSeparator );
              10000004, extraMenuEnable + grayFlag );
   setMenu.Add( "  ブックマークがなくても メニューを表示する (&N)"
   subMenu.Add( "「先頭行/最終行/行頭 へジャンプ」 を表示する (&P)",
            , 10000004, ss.extraMenuEnable + grayFlag );
              10000005, menuPinEnable + grayFlag );
   setMenu.Add( "「先頭行/最終行/行頭 へジャンプ」 を表示する (&P)"
   subMenu.Add( "  " + subMenuHeight + " 件ごとに 「キャンセル」 を表示する (&C)",
            , 10000005, ss.menuPinEnable + grayFlag );
              10000012, menuScrollEnable + grayFlag );
   setMenu.Add( "  " + subMenuHeight
   subMenu.Add( "----", 0, meMenuSeparator );
            + " 件ごとに 「キャンセル」 を表示する (&C)"
   subMenu.Add( "「行の表示方法」 を自動設定する (&A)",
            , 10000006, ss.menuScrollEnable + grayFlag );
              10000006, autoLineModeEnable + grayFlag );
   setMenu.Add( "----", 0, meMenuSeparator );
   subMenu.Add( " 行数を 「論理行」 で表示する (&L)",
   setMenu.Add( "「行の表示方法」 を自動設定する (&A)"
              10000007, !lineColumnView + grayFlag2 );
            , 10000007, ss.autoLineModeEnable + grayFlag );
   subMenu.Add( " 行数を 「表示行」 で表示する (&V)",
   setMenu.Add( "行数を 「論理行」 で表示する"
              10000007, lineColumnView + grayFlag2 );
            + ( ss.lineColumnView ? " (&L)" : "" )
   subMenu.Add( "----", 0, meMenuSeparator );
            , 10000008, ! lineColumnView + autoLineModeGrayFlag );
   subMenu.Add( "「分割サブメニュー」 を表示する (&D)"
   setMenu.Add( "行数を 「表示行」 で表示する"
             , 10000013, subMenuEnable + grayFlag );
            + ( ss.lineColumnView ? "" : " (&V)" )
   subMenu.Add( "  サブメニューの分割単位を 10行 増やす (&X) \t"
            , 10000008, lineColumnView + autoLineModeGrayFlag );
             + subMenuHeight
   setMenu.Add( "----", 0, meMenuSeparator );
            + ( subMenuHeight >= 100 ? "" : " → " + ( subMenuHeight + 10 ) )
   setMenu.Add( "「分割サブメニュー」 を表示する (&D)"
             , 10000014, maxHeightFlag );
             , 10000009, ss.subMenuEnable + grayFlag );
   subMenu.Add( "  サブメニューの分割単位を 10行 減らす (&Z) \t"
   setMenu.Add( "・ メインメニューの中に「 1 - " + ss.subMenuHeight
             + subMenuHeight
            + " 件目: \u25B6」 を表示する"
            + ( subMenuHeight < 20 ? "" : " → " + ( subMenuHeight - 10 ) )
            + ( ss.subMenuStyle ? " (&T)" : "" )
             , 10000015, minHeightFlag );
            , 10000010, ! ss.subMenuStyle + subMenuFlag );
   subMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "・ 「" + ss.subMenuHeight
   subMenu.Add( "  メニューの表示幅を 10文字 増やす (&+)\t"
            + " 件ずつに分割して表示 \u25B6」"
             + menuWidth
            + " の中に表示する" + ( ss.subMenuStyle ? "" : " (&T)" )
            + ( menuWidth > 100 ? "" : " → " + ( menuWidth + 10 ) ),
            , 10000010, ss.subMenuStyle + subMenuFlag );
              10000008, maxWidthFlag + grayFlag );
  setMenu.Add( "  サブメニューの分割単位を 10行 増やす (&X) \t"
   subMenu.Add( "  メニューの表示幅を 10文字 減らす (&-)\t"
             + ss.subMenuHeight + ( ss.subMenuHeight >= 100 ? ""
             + menuWidth
            : " → " + ( ss.subMenuHeight + 10 ) )
            + ( menuWidth < 30 ? "" : " → " + ( menuWidth - 10 ) ),
             , 10000011, maxHeightFlag );
              10000009, minWidthFlag + grayFlag );
   setMenu.Add( "  サブメニューの分割単位を 10行 減らす (&Z) \t"
   subMenu.Add( " 半角 a-z を全角で表示する (&F)",
             + ss.subMenuHeight + ( ss.subMenuHeight < 20 ? ""
              10000010, toFullWidth + grayFlag );
            : " → " + ( ss.subMenuHeight - 10 ) )
   subMenu.Add( "----", 0, meMenuSeparator );
             , 10000012, minHeightFlag );
   subMenu.Add( " 入力カーソル の位置 にメニューを表示する"
   setMenu.Add( "----", 0, meMenuSeparator );
             + ( menuPosMouse ? " (&M)" : "" ),
   setMenu.Add( "  メニューの表示幅を 10文字 増やす (&+)\t"
              10000011, !menuPosMouse + grayFlag );
             + ss.menuWidth + ( ss.menuWidth > 100 ? ""
   subMenu.Add( " マウスポインタの位置 にメニューを表示する"
            : " → " + ( ss.menuWidth + 10 ) )
             + ( menuPosMouse ? "" : " (&M)" ),
            , 10000013, maxWidthFlag );
              10000011, menuPosMouse + grayFlag );
   setMenu.Add( "  メニューの表示幅を 10文字 減らす (&-)\t"
   subMenu.Add( "----", 0, meMenuSeparator );
             + ss.menuWidth + ( ss.menuWidth < 30 ? ""
   subMenu.Add( "----", 0, meMenuSeparator );
            : " → " + ( ss.menuWidth - 10 ) )
   subMenu.Add( "  設定内容をロックする (&S)", 10000000, !settingEnable*1 );
            , 10000014, minWidthFlag );
   subMenu.Add( "", 0, meMenuSeparator );
  setMenu.Add( "----", 0, meMenuSeparator );
   subMenu.Add( "「ジャンプ」マクロの JS ファイルを開く (&O)", 10000016 );
   setMenu.Add( "半角 -z と記号を全角で表示する (&F)\t"
   subMenu.Add( "「ジャンプ」マクロの JSON ファイルを開く (&J)", 10000017 );
            , 10000015, ( ss.toWideWidth === 2 ) + grayFlag );
   subMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "・ 半角英・記号の文字間隔を調整する (&W)\t"
   subMenu.Add( "  設定を初期化する (&I)", 10000018, grayFlag );
            , 10000016, ( ss.toWideWidth === 1 ) + grayFlag );
   subMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "・ 半角英数記号を半角のまま表示する (&H)\t"
   subMenu.Add( "  キャンセル\t& ", 0 );
            , 10000017, ! ss.toWideWidth + grayFlag );
   setMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "入力カーソル の位置 にメニューを表示する"
             + ( ss.menuPosMouse ? " (&M)" : "" )
            , 10000018, ! ss.menuPosMouse + grayFlag );
   setMenu.Add( "マウスポインタの位置 にメニューを表示する"
             + ( ss.menuPosMouse ? "" : " (&M)" )
            , 10000018, ss.menuPosMouse + grayFlag );
   setMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "  設定内容をロックする (&S)"
            , 10000000, ! ss.settingEnable *1 );
   setMenu.Add( "", 0, meMenuSeparator );
   setMenu.Add( "「ジャンプ」マクロの JS ファイルを開く (&O)"
            , 10000100 );
   setMenu.Add( "「ジャンプ」マクロの JSON ファイルを開く (&J)"
            , 10000101 );
   setMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "  設定を初期化する (&I)", 10000102, grayFlag );
   setMenu.Add( "----", 0, meMenuSeparator );
   setMenu.Add( "  キャンセル\t& ", 0 );
  return setMenu;
}
}


1,046行目: 1,137行目:
  * 関数 SettingsChange( num )
  * 関数 SettingsChange( num )
  * ポップアップメニューで選択した項目の設定状態を変更する
  * ポップアップメニューで選択した項目の設定状態を変更する
* ※ 設定変更でのメニュー再表示 do - while ループのさいに
*    JSON の再読みこみを省略するために
*    ローカル変数 = JSON 項目 = 設定値  の形式で記述する
  */
  */
function SettingsChange( num ) {
function SettingsChange( num ) {
   // var jsonPath = JsonDir() + "\\" + jsonName + ".json";
   var isChanged = true;
  var sIsChanged = true;
   switch ( num ) {
   switch ( num ) {
    case 10000000: // 設定内容をロックする
  case 10000001: // ジャンプ先の行まで 範囲選択する
      settingEnable = setting.settingEnable
    blockSelectEnable = setting.blockSelectEnable
                    = ! settingEnable;
                      = ! blockSelectEnable;
      break;
    break;
    case 10000001: // ジャンプ先の行まで 範囲選択する
  case 10000002: // もとの選択範囲を ジャンプ後の範囲選択に含める
      blockSelectEnable = setting.blockSelectEnable
    keepInitialSelect = setting.keepInitialSelect
                        = ! blockSelectEnable;
                      = ! keepInitialSelect;
      break;
    break;
    case 10000002: // もとの選択範囲を ジャンプ後の範囲選択に含める
  case 10000003: // 下の行にジャンプしたときに 行全体を選択
      keepInitialSelect = setting.keepInitialSelect
    endOfBookmarkLine = setting.endOfBookmarkLine
                        = ! keepInitialSelect;
                      = ! endOfBookmarkLine;
      break;
    break;
    case 10000003: // 下の行にジャンプしたときに 行全体を選択
  case 10000004: // ブックマークがなくても メニューを表示する
      endOfBookmarkLine = setting.endOfBookmarkLine
    extraMenuEnable = setting.extraMenuEnable
                        = ! endOfBookmarkLine;
                    = ! extraMenuEnable;
      break;
    break;
    case 10000004: // ブックマークがなくても メニューを表示する
  case 10000005: // 「先頭行/最終行/行頭 へジャンプ」 を表示する
      extraMenuEnable = setting.extraMenuEnable
    menuPinEnable = setting.menuPinEnable
                      = ! extraMenuEnable;
                  = ! menuPinEnable;
      break;
    break;
    case 10000005: // 「先頭行/最終行/行頭 へジャンプ」 を表示する
  case 10000006: // 20 件* ごとに 「キャンセル」 を表示する
      menuPinEnable = setting.menuPinEnable
    menuScrollEnable = setting.menuScrollEnable
                    = ! menuPinEnable;
                    = ! menuScrollEnable;
      break;
     break;
     case 10000006: // 「行の表示方法」 を自動設定する
  case 10000007: // 「行の表示方法」 を自動設定する
      autoLineModeEnable = setting.autoLineModeEnable
    autoLineModeEnable = setting.autoLineModeEnable
                        = ! autoLineModeEnable;
                      = ! autoLineModeEnable;
      break;
    break;
    case 10000007: // 行数を 「論理行/表示行」 で表示する
  case 10000008: // 行数を 「論理行/表示行」 で表示する
      lineColumnView = setting.lineColumnView
    lineColumnView = setting.lineColumnView
                    = ! lineColumnView;
                  = ! lineColumnView;
      break;
    break;
     case 10000008: // メニューの表示幅を 10文字 増やす
  case 10000009: // 「分割サブメニュー」 を表示する
      menuWidth = setting.menuWidth += 10;
    subMenuEnable = setting.subMenuEnable
      break;
                  = ! subMenuEnable;
     case 10000009: // メニューの表示幅を 10文字 減らす
     break;
      menuWidth = setting.menuWidth -= 10;
  case 10000010: // 「20* 件ずつに分割して表示 ▶」のなかに表示する
      break;
    subMenuStyle = setting.subMenuStyle
    case 10000010: // 半角英文字を全角で表示する
                = Number( ! subMenuStyle );
      toFullWidth = setting.toFullWidth
    break;
                  = ! toFullWidth;
  case 10000011: // サブメニューの分割単位を 10行 増やす
      break;
    subMenuHeight = setting.subMenuHeight += 10;
    case 10000011: // 入力カーソル/マウスポインタ の位置 にメニューを表示する
    break;
      menuPosMouse = setting.menuPosMouse
  case 10000012: // サブメニューの分割単位を 10行 減らす
                  = ! menuPosMouse;
     subMenuHeight = setting.subMenuHeight -= 10;
      break;
    break;
    case 10000012: // 20 件* ごとに 「キャンセル」 を表示する
  case 10000013: // メニューの表示幅を 10文字 増やす
      menuScrollEnable = setting.menuScrollEnable
    menuWidth = setting.menuWidth += 10;
                      = ! menuScrollEnable;
    break;
      break;
  case 10000014: // メニューの表示幅を 10文字 減らす
    case 10000013: // 「分割サブメニュー」 を表示する
    menuWidth = setting.menuWidth -= 10;
      subMenuEnable = setting.subMenuEnable
    break;
                    = ! subMenuEnable;
  case 10000015: // 半角 a-z と記号を全角で表示する
      break;
    toWideWidth = setting.toWideWidth = 2;
    case 10000014: // サブメニューの分割単位を 10行 増やす
    break;
      subMenuHeight = setting.subMenuHeight += 10;
  case 10000016: // 半角英・記号の文字間隔を調整する
      break;
    toWideWidth = setting.toWideWidth = 1;
    case 10000015: // サブメニューの分割単位を 10行 減らす
    break;
      subMenuHeight = setting.subMenuHeight -= 10;
  case 10000017: // 半角英数記号を半角のまま表示する
      break;
    toWideWidth = setting.toWideWidth = 0;
    case 10000016: // 「ジャンプ」マクロの JS ファイルを開く
    break;
      sIsChanged = false;
  case 10000018: // 入力カーソル/マウスポインタ の位置 にメニューを表示する
      Status = " " + ScriptFullName;
    menuPosMouse = setting.menuPosMouse
      OpenJumpJS( "setting.settingEnable = " );
                = ! menuPosMouse;
      break;
    break;
    case 10000017: // 「ジャンプ」マクロの JSON ファイルを開く
  case 10000000: // 設定内容をロックする
      sIsChanged = false;
    settingEnable = setting.settingEnable
      OpenJumpJson( jsonName );
                  = ! settingEnable;
      break;
    break;
    case 10000018: // 設定を初期化する
  case 10000100: // 「ジャンプ」マクロの JS ファイルを開く
      sIsChanged = false;
    isChanged = false;
      CheckJsonFile( jsonName );
    Status = " " + ScriptFullName;
      break;
    new ActiveXObject( "WScript.Shell" )
    default:
    .Run( '"' + editor.FullName + '" "' + ScriptFullName + '"' );
      sIsChanged = false;
    break;
      break;
  case 10000101: // 「ジャンプ」マクロの JSON ファイルを開く
    isChanged = false;
    OpenJumpJson( jsonName, decode = false, toWideWidth );
    break;
  case 10000102: // 設定を初期化する
    isChanged = false;
    CheckJsonFile( jsonName, decode = false, toWideWidth );
    break;
  default:
    sIsChanged = false;
    break;
   }
   }
   if ( sIsChanged ) {
   if ( isChanged ) {
     IO.Serialize( setting, jsonName );
     IO.Serialize( setting, jsonName );
     Status = " 設定の変更を保存しました。";
     Status = "  設定の変更を保存しました。";
   }
   }
}
}


/**
/**
  * 関数 OpenJumpJS( str )
  * 関数 OpenJumpJson( setting, jsonName )
* このマクロの JS ファイルを開いて設定項目の行にジャンプする
* 引数: 検索文字列(設定項目の行の文字列)
*/
function OpenJumpJS( str ) {
  Redraw = false;
  var targetStr = str || "";
  var eCount = editors.Count;
  var dCount,  dItem,  ee, dd;
  var isOpen = false;
  OuterLoop:
  for ( var j = 0; j < eCount; j ++ ) {
    dCount = editors.Item( j ).documents.Count;
    for ( var i = 0; i < dCount; i ++ ) {
      dItem = editors.Item( j ).documents.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.SetActivePos( settingPos + targetStr.length );
  // js.selection.WordRight( true ); // true を範囲選択
  ScrollY = js.selection.GetActivePointY( mePosView );
  Redraw = true;
}
 
/**
* 関数 OpenJumpJson( jsonName )
  * JSON ファイルを開く
  * JSON ファイルを開く
  */
  */
function OpenJumpJson( jsonName ) {
function OpenJumpJson( jsonName, decode, toWideWidth ) {
   IO.Serialize( setting, jsonName );
   IO.Serialize( setting, jsonName );
   Sleep( 500 );
   Sleep( 500 );
1,184行目: 1,244行目:
   var jsonPath = jsonDir + "\\" + jsonName + ".json";
   var jsonPath = jsonDir + "\\" + jsonName + ".json";
   if ( IO.Path.IsExist( jsonPath )
   if ( IO.Path.IsExist( jsonPath )
      && JsonContents( jsonPath ).length ) {
  && ( json = JsonContents( jsonPath, decode, toWideWidth ) ).length ) {
     var confirmStr = "設定ファイルは正常です \n\n"
     var confirmStr = "設定ファイルは正常です \n\n"
                   + JsonContents( jsonPath )
                   + json + "設定ファイルを開きますか? ";
                  + "設定ファイルを開きますか? ";
     if ( Confirm( confirmStr ) ) {
     if ( Confirm( confirmStr ) ) {
       var WshShell = new ActiveXObject( "WScript.Shell" );
       new ActiveXObject( "WScript.Shell" )
       WshShell.Run( '"' + editor.FullName + '" "' + jsonPath + '"' );
       .Run( '"' + editor.FullName + '" "' + jsonPath + '"' );
     }
     }
   } else {
   }
     Alert( "設定ファイルがありません \n"
  else {
        + jsonDir + "  " );
     Alert( "設定ファイルがありません \n" + jsonDir + "  " );
   }
   }
}
}
1,202行目: 1,261行目:
  * JSON ファイルの初期化/実在確認
  * JSON ファイルの初期化/実在確認
  */
  */
function CheckJsonFile( jsonName ) {
function CheckJsonFile( jsonName, decode, toWideWidth ) {
   var jsonDir = JsonDir();
   var jsonDir = JsonDir();
   var jsonPath = jsonDir + "\\" + jsonName + ".json";
   var jsonPath = jsonDir + "\\" + jsonName + ".json";
1,210行目: 1,269行目:
     IO.Serialize( initialSettings, jsonName );
     IO.Serialize( initialSettings, jsonName );
     Sleep( 500 );
     Sleep( 500 );
     var alertStr = ( IO.Path.IsExist( jsonPath )
     var msg = ( IO.Path.IsExist( jsonPath )
                    && JsonContents( jsonPath ).length )
    && ( json = JsonContents( jsonPath, decode, toWideWidth ) ).length )
                ? "設定ファイルは正常です \n\n"
    ? "設定ファイルは正常です \n\n" + json
                  + JsonContents( jsonPath )
    : "設定ファイルがありません \n" + jsonDir + "  ";
                : "設定ファイルがありません \n"
     Alert( msg );
                  + jsonDir + "  ";
     Alert( alertStr );
   }
   }
}
}
1,226行目: 1,283行目:
function JsonDir() {
function JsonDir() {
   var jsonDir;
   var jsonDir;
   if ( IO.Path.IsExist( editor.FullName.replace( /\.exe$/i, ".ini" ) ) ) {
   if ( IO.Path.IsExist(
  editor.FullName.replace( /\.exe$/i, ".ini" ) ) ) {
     jsonDir = editor.FullName.replace( /[^\\]+$/i, "" )
     jsonDir = editor.FullName.replace( /[^\\]+$/i, "" )
             + "Macros\\MacroSettings";
             + "Macros\\MacroSettings";
   } else {
   }
     var WshShell = new ActiveXObject( "WScript.Shell" );
  else {
    jsonDir = WshShell.ExpandEnvironmentStrings( "%APPDATA%" )
     jsonDir = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
             + "\\Mery\\MacroSettings";
             + "\\Mery\\MacroSettings";
   }
   }
1,238行目: 1,297行目:


/**  
/**  
  * 関数 JsonContents( jsonPath [, bool] )
  * 関数 JsonContents( jsonPath, decode, toWideWidth )
  * JSON ファイルの文字列をメッセージボックス用に整形する
  * JSON ファイルの文字列をメッセージボックス用に整形する
*
* 第1引数は JSON ファイルのパス
* 第2引数は真偽値(省略可、true なら \uHHHH をデコードする)
  */
  */
function JsonContents( jsonPath, bool ) {
function JsonContents( jsonPath, decode, toWideWidth ) {
   var contents = ( jsonPath + "  \n"
   var json = IO.LoadFromFile( jsonPath )
  + IO.LoadFromFile( jsonPath )
            .replace( /^\{/, "\n{\n  " )
      .replace( /^\{/, "\n{\n  " )
            .replace( /\}$/g, "\n}\n\n" )
      .replace( /\}$/g, "\n}\n\n" )
            .replace( /,"/g, " ,\n  \"" )
      .replace( /,"/g, " ,\n  \"" )
            .replace( /":/g, "\": " );
      .replace( /":/g, "\": " )
   if ( decode ) {
  );
   if ( bool ) {
     // 「テキスト整形」マクロより >> 符号化/復号化 >> \uHHHH デコード
     // 「テキスト整形」マクロより >> 符号化/復号化 >> \uHHHH デコード
     var Decode_uHHHH = function( str ) {
     json = json.replace( /\\u([0-9A-Fa-f]{4})/g, function( s, n ) {
      return str.replace( /\\u([0-9A-Fa-f]{4})/g, function( s, n ) {
      return String.fromCharCode( Number( "0x" + n ) );
        return String.fromCharCode( Number( "0x" + n ) );
    } );
      } );
    };
    contents = Decode_uHHHH( contents );
   }
   }
   if ( toFullWidth ) {
   if ( toWideWidth ) {
     // 半角アルファベットの小文字を全角にするなら
     // 半角アルファベットの小文字を全角にするなら
     contents = contents.replace( /[a-z]/g,
     json = json.replace( /[a-z]/g, function( tmp ) {
      function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
    } );
      } );
   }
   }
   return contents;
   return jsonPath + "  \n" + json;
}
}
/**
* ---------- ▼ 更新履歴 ▼ ----------
* 2019/03/29:
* ・sukemaru版をマクロライブラリに投稿。
*
* 2019/04/08:
* ・Quit() の削除と、軽微な変更。
*
* 2019/04/16:
* ・Mery 2.7.0 でのブックマークの仕様変更に対応。
* ・【include版】を追加。
*
* 2019/12/05:
* ・「ブックマークを設定/解除」 をメニューに追加
* ・メニュー内にブックマーク件数を表示
* ・「もとの選択範囲をジャンプ後の範囲選択に含める」 を設定項目に追加
*
*  【include版】
* ・ポップアップメニュー生成コードを関数セクションに移動
* ・「分割サブメニュー」 を追加
* ・20* 行ごとに 「キャンセル」 を追加(スペースキーでスクロール)
*  「キャンセル」 行の追加単位は 「分割サブメニュー」 の分割設定にあわせた
* ・「設定変更」 したときのメニュー表示のループ処理を追加
* ・「半角 a-z を全角表示する」 を設定項目に追加
* ・その他、設定項目の追加、動作コードの変更
*/
</source>
</source>

2020年6月24日 (水) 23:23時点における版

goat 版

ポップアップメニューでジャンプ先を選択。範囲指定中はジャンプ先まで選択範囲を拡大します。

Mery Ver.1.1.2.2840 および Ver.2.0.9.3936 での動作を確認しています。 (2012.09.24)

 #title="ブックマーク一覧"
 /*
 * ブックマーク一覧をポップアップメニューにして選択ジャンプ
 * Mery標準のブックマークが対象
 * 範囲選択中の場合は選択範囲を拡大
 */
 (function(){
   // 描画停止
   Redraw = false;
   with(document.selection){
     var flgBlock = !isEmpty;
     //カーソル位置の保存
     var activePos = GetActivePos();
     var anchorPos = GetAnchorPos();
     var sX = ScrollX;
     var sY = ScrollY;
 
     var bookmarks = new Array();
     StartOfDocument(false);
     // 先頭行がブックマークされてないか
     var isTopMarked = false;
     CharRight(false);
     if(PreviousBookmark()){
       isTopMarked = true;
       SelectLine();
       menuKey = Text.slice(0,24).replace(/\t/g, "\\t");
       Collapse();
       bookmarks.push("Line " + GetActivePointY(mePosLogical) + ":\t" + menuKey);
     } else {
       StartOfDocument(false);
     }
     while(NextBookmark()){
       SelectLine();
       menuKey = Text.slice(0, 24).replace(/\t/g, "\\t");
       Collapse();
       bookmarks.push("Line " + GetActivePointY(mePosLogical) + ":\t" + menuKey);
     }
     var bmcount = bookmarks.length;
     if(bmcount == 0){
       //カーソル位置の復帰
       SetActivePos(activePos);
       SetAnchorPos(anchorPos);
       ScrollX = sX;
       ScrollY = sY;
     } else {
       var BookmarkMenu = CreatePopupMenu();
       for(var i = 0; i < bmcount; i++){
         //メニューのアクセスキーも1から始まるほうが便利
         BookmarkMenu.Add("&" + (i+1) + " " + bookmarks[i], i+1)
       }
       var ret = BookmarkMenu.Track(0);
       if(ret == 0){
         //カーソル位置の復帰
         SetActivePos(activePos);
         SetAnchorPos(anchorPos);
         ScrollX = sX;
         ScrollY = sY;
       } else {
         StartOfDocument(false);
         if(isTopMarked)ret--;
         for(i = 0; i < ret; i++){ NextBookmark(); }
       }
     }
     if(flgBlock){
       //ジャンプ前の選択開始位置からジャンプ後のカーソル位置まで範囲選択
       SetAnchorPos(anchorPos);
     }
   }
   // 描画再開
   Redraw = true;
 })()

Mery ver 2.7.0 以降への対応

goat 版を Mery ver 2.7.0 以降で使用する場合は、20 行目付近を以下のように書き換えてください。
変更しない場合、ドキュメントの 1 行目がブックマークされていてもポップアップメニューに表示されなくなります。 (2019/04/16 sukemaru)

変更前
18.    var bookmarks = new Array();
19.    StartOfDocument(false);
20.    // 先頭行がブックマークされてないか
21.    var isTopMarked = false;
22.    CharRight(false);
23.    if(PreviousBookmark()){
24.      isTopMarked = true;
変更後
18.    var bookmarks = new Array();
19.    // StartOfDocument(false);
20.    // 先頭行がブックマークされてないか
21.    var isTopMarked = false;
22.    SetActivePoint(mePosLogical, 1, 2);
23.    if(PreviousBookmark()){
24.      isTopMarked = true;


sukemaru 版

goat 版を元にして、ポップアップメニューを表示するまでの速度を改善し、動作設定をカスタマイズできるようにしました。

▼ goat 版からの変更点 ▼
  • ソースコード内の設定項目から "表示行" / "論理行" の選択可(初期値は "論理行")
  • 設定項目で "ジャンプ先までの範囲選択" はしない状態を初期値にした
  • ブックマーク行の検索 ~ ポップアップメニューの表示 までの速度を改善
  • ポップアップメニューの体裁を変更(「検索ジャンプ」マクロにあわせた)
  • ステータスバーにブックマーク件数などの情報を表示
  • 「ブックマークがありません」メニュー。
  • ジャンプしたときのスクロール位置を調整。
  • ジャンプ先まで範囲選択するときの先頭/末尾を調整。
  • 「先頭行/最終行 へジャンプ」をメニューにピン止め表示。
  • 「ブックマークを設定/解除」をメニューの先頭にピン止め表示。
  • ポップアップメニューだと読み取りづらい半角英小文字・と ascii 記号の一部を全角で表示。


ブックマークジャンプ(通常版)


  • Mery でプログラミング用のフォントを使っている人だと、ポップアップメニュー内で半角 ¥ 記号 (U+005C) がバックスラッシュ (U+005C) にならないのは気落ち悪いかも? ということで、ソースコード内の関数 MenuKey() のコードのコメントアウトしてある行(300行目付近)をアンコメントすると "擬似的に" バックスラッシュ化できます
    (※ (U+2216) に置換して表示します)。


  • 行番号の桁埋め(右寄せ/空白埋め)用の空白文字を設定する項目 var blankChr = " "; を追加し、初期値を半角空白 " "(U+0020)にしました(※ これまで MS UI Gothic に最適化してあった桁埋め方法をカスタマイズできるようにした)。
MS UI Gothic では2分アキ(EN SPACE) "\u2002"
Meiryo UI では和字間隔(全角空白) "\u3000"
Segoe UI では図形間隔(FIGURE SPACE) "\u2007" にすると具合がよいようです。


ダウンロード

ダウンロード:ファイル:ブックマークジャンプ.zip」(アイコン入り) 
最終更新: 2020/06/24

【共通】:行番号の桁埋め用の空白文字を指定する設定項目などを追加
【include版】:分割サブメニューの表示形式のカスタマイズ用設定項目を追加
オマケとして [ 編集 ] メニューのブックマーク関連コマンドのアイコン化用マクロ×4


ソースコード

  • このマクロではポップアップメニューの表示に unicode 文字を使用します。

ファイルに保存するさいは、文字コードを shift_JIS にしないでください(UTF-8 や Unicode で保存する)。

#title = "ブックマーク一覧ジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#icon = "bookmark_list.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",243

/**
 * ---------------------------------------------------------
 * 「ブックマーク一覧ジャンプ」
 *   Orginal created by: Kuro, goat (2012/06/22 - 2012/09/24)
 *   Modified by:        sukemaru   (2018/08/08 - 2020/06/07)
 * ---------------------------------------------------------
 */

var start = new Date();	  // 所要時間計測(開始)

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

// ■ ジャンプする前に選択範囲があったときはジャンプ先の行まで範囲選択する?
var blockSelectEnable = false;  // (true 範囲選択する / false 範囲選択しない)

    // ■ もとの選択範囲をジャンプ後の範囲選択に含める?
    var keepInitialSelect = false;  // (true 含める / false 含めない)

    // ■ 下の行にジャンプしたとき、ジャンプ先の行全体(論理行)を選択範囲に含める?
    var endOfBookmarkLine = false;  // (true 含める / false 含めない)


// ■ 行番号の表示方法を Mery.ini から「自動」で読み込む?
var autoLineModeEnable = false;  // (true 自動読み込み / false 手動設定)

    // ■ 行番号の表示方法(手動設定用)
    var lineColumnView = 0;	  // ( 0 論理行 / 1 表示行 )


// ■ 「ブックマークがありません」メニューを表示する?
var extraMenuEnable = true;  // (true 表示する / false 表示しない)

// ■ ポップアップメニューに「先頭行/最終行 へジャンプ」をピン止め表示する?
var menuPinEnable = true;  // (true 表示する / false 表示しない)

// ■ ポップアップメニュー内の 30件* ごとに「キャンセル」を表示する?
var menuScrollEnable = false;  // (true する / false しない)

    // ■ 「キャンセル」の挿入ピッチ
    // ※ 10 - 100 のあいだの範囲の 10 の倍数で指定すること
    var subMenuHeight = 30;  // ◆初期値 = 30;


// ■ ポップアップメニューに表示する文字数の目安
var menuWidth = 65;  // (全角/半角の区別なし)

// ■ 半角英文字を全角で表示する	[!"%'(),.:;@\[\]`a-z{|}]
var toWideWidth = 0;  // (0 しない / 1 文字間を広げる / 2 全角にする)

// ■ ポップアップメニューを表示する位置
var menuPosMouse = true;  // ( true マウス位置 / false カーソル位置 )


// ■ 連番の桁埋め(右寄せ/空白埋め)用空白文字の定義
var blankChr = " ";  // " " or "\u2002" or "\u3000" or "\u2007" or ...

  /* 半角数字の幅に等しい空白文字として
     MS UI Gothic では「2分アキ」 = EN SPACE: "\u2002"
     (MeiryoKe_UI Gothic は MS UI Gothic に同じ)
     Meiryo UI では「和字間隔」 = 全角空白: "\u3000"
     Segoe UI では「図形間隔」 = FIGURE SPACE: "\u2007"
     にすると具合がよさそうですが、ウエイトによって幅が変わるので... */

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

// 連番の桁埋め(右寄せ/空白埋め)用
var b1 = ( ! blankChr || ( "" + blankChr ).length > 1 )
       ? " " : blankChr;
Object.prototype.PadSpace = function(len, chr) {
  var dgt = String(this);
  len = Number(len) || dgt.length;
  chr = chr ? chr.toString() : b1; // (b1 = blankChr || " ")
  if (len < 0 || len < dgt.length || chr.length !== 1) 
    return dgt;
  for (var i = 0; i < len; i++)
    chr += chr;
  return (chr + dgt).slice( - len);
};
// Mery.ini から「行の表示方法」を取得する
if ( autoLineModeEnable ) {
  lineColumnView = GetIniOptionNum( "LineColumnView" );
}
// 表示行/論理行 の定数
var posMode = lineColumnView ? mePosView : mePosLogical;
var lineMode = lineColumnView ? meGetLineView : 0;
// 全体の行数
var d = editor.ActiveDocument;
var lines = d.GetLines( lineMode );
// カーソルと選択範囲の位置を保存
var s = d.selection;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var ay = s.GetActivePointY( posMode );
var sx = ScrollX,  sy = ScrollY;
// ブックマーク行の変数
var bmArray = [],  bmY = 0,  bmStr = "",  label = "";
// アクティブ行がブックマークされているか
var flag = 0,  isBookmarked = 0;

// ブックマーク行を検索
Redraw = false;
// 先頭行がブックマークされているか
s.SetActivePoint( mePosLogical, 1, 2 );
if ( s.PreviousBookmark() ) {
  bmY = s.GetActivePointY( posMode );
  bmStr = d.GetLine( bmY, lineMode );
  label = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
  if ( bmY === ay ) { flag = 1;  isBookmarked = 1; }
  bmArray.push( { str: label,  id: bmY,  flag: flag } );
}
// 2行目以降のブックマークを探す
s.SetActivePos( 0 );
while ( s.NextBookmark() ) {
  bmY = s.GetActivePointY( posMode );
  bmStr = d.GetLine( bmY, lineMode );
  label = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
  if ( bmY === ay ) { flag = 1;  isBookmarked = 1; }
  else { flag = 0; }
  bmArray.push( { str: label,  id: bmY,  flag: flag } );
}
// カーソル位置と選択範囲を復帰
s.SetActivePos( act );  s.SetAnchorPos( anc );
ScrollX = sx;  ScrollY = sy;
Redraw = true;

// ブックマークの件数
var bmCount = bmArray.length;
var numWidth = ( ( menuPinEnable || ! bmCount ) ? lines : bmY )
               .toString().length;

// ステータスラベル
var status1 = ( bmCount )
? " ブックマーク: "
  + bmCount.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
  + " 件 "
: " ブックマークがありません。 ";
var status2 = ( bmCount ? "/ " : "" )
+ "全体の行数: "
+ lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
+ ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );

// アクティブ行のチェックマークフラグ (meMenuChecked = 1)
var Check = function( num ) { return ( num === ay ) *1; }

// ピン止めアイテム
var bmPin     = ay.PadSpace( numWidth ) + ": "
              + "ブックマークを設定/解除 (&B)";
var countPin  = "".PadSpace( numWidth )
              + " ▼ " + status1 + " ▼";
var cancelPin = "".PadSpace( numWidth )
              + " キャンセル\t& ";
var topPin    = ( 1 ).PadSpace( numWidth ) + ": "
              + "** 先頭行へジャンプ (&T) **";
var endPin    = lines.PadSpace( numWidth ) + ": "
              + "** 最終行へジャンプ (&E) **";
var actPin    = ay.PadSpace( numWidth ) + ": "
              + "** 行頭へジャンプ (&A) **";

// ポップアップメニューの準備
var bmMenu = CreatePopupMenu();

// メニューの最上部に「設定/解除」をピン止め
if ( bmCount || extraMenuEnable ) {
  bmMenu.Add( bmPin, 20000000, isBookmarked );
  bmMenu.Add( "----", 0, meMenuSeparator );
}

// 「ブックマーク一覧」ポップアップメニュー
if ( bmCount ) {
  bmMenu.Add( "----", 0, meMenuSeparator );
  // メニュー上部のピン止めアイテム
  if ( menuPinEnable
  && ( bmArray[0].id > 1 || ! isBookmarked && ay > 1 && ay < lines ) ) {
    if ( bmArray[0].id > 1 ) {
      bmMenu.Add( topPin, 1, Check( 1 ) );  // 「先頭行へジャンプ」
    }
    if ( ! isBookmarked && ay > 1 && ay < lines ) {
      bmMenu.Add( actPin, ay, meMenuChecked );  // 「行頭へジャンプ」
    }
    if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ].id !== lines ) {
      bmMenu.Add( endPin, lines, Check( lines ) );  // 「最終行へジャンプ」
    }
    bmMenu.Add( "----", 0, meMenuSeparator );
  }
  // ブックマーク一覧
  bmMenu.Add( countPin, 0, 0 );  // ▼ ブックマーク: n 件 ▼
  for ( var i = 0, bm, num; i < bmCount; i ++ ) {
    if ( i % 10 === 0 && i > 0 ) {
      bmMenu.Add( "----", 0, meMenuSeparator );  // 10行ごとにセパレータ
      if ( menuScrollEnable && i % subMenuHeight === 0 ) {
        bmMenu.Add( cancelPin, 0 );  // 30行* ごとに「キャンセル」
        bmMenu.Add( "----", 0, meMenuSeparator );
      }
    }
    // ブックマーク行をポップアップメニューに追加
    bm  = bmArray[i];
    num = bm.id.PadSpace( numWidth ).replace( /\d$/, "&$&: " );
    bmMenu.Add( num + bm.str, bm.id, Check( bm.id ) );
  }
  // メニュー下部のピン止めアイテム
  if ( menuPinEnable && bmArray[ bmCount -1 ].id !== lines ) {
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( endPin, lines, Check( lines ) );  // 「最終行へジャンプ」
  }
  if ( menuScrollEnable && bmCount > subMenuHeight ) {
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( cancelPin, 0 );  // 「キャンセル」
  }
}

// 「ブックマークがありません」ポップアップメニュー
else if ( extraMenuEnable ) {
  // 「ブックマークがありません」
  bmMenu.Add( "※ " + status1 + " ※", 0, meMenuGrayed );
  if ( ! menuPinEnable ) {
    bmMenu.Add( " " + status2, 0 );  // 全体の行数
  }
  // ピン止めアイテム
  if ( menuPinEnable ) {
    if ( lines > 1 ) {
      bmMenu.Add( "----", 0, meMenuSeparator );	
      bmMenu.Add( topPin, 1, Check( 1 ) );  // 「先頭行へジャンプ」
      if ( ay > 1 && ay < lines ) {
        bmMenu.Add( actPin, ay, meMenuChecked );  // 「行頭へジャンプ」
      }
      bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
    }
    else {
      bmMenu.Add( actPin, ay, meMenuChecked );  // 「行頭へジャンプ」
    }
  }
}

// ステータスとポップアップメニューを表示
Status = status1 + status2 + TimerElapsed( new Date(), start );
var y = bmMenu.Track( menuPosMouse );

// ブックマークを設定/解除
if ( y === 20000000 ) {
  editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}
// ジャンプ
else if ( y ) {
  s.SetActivePoint( posMode, 1, y );
  var yy = s.GetActivePointY( mePosView );

  // アクティブ行へのジャンプではスクロール位置をリセット
  if ( y === ay ) { ScrollY = yy }

  // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
  if ( blockSelectEnable && act !== anc ) {
    var jumpDown = ( ay < y );
    // もとの選択範囲の文字列を含んだままにする
    if ( keepInitialSelect ) {
      var tp = Math.min( anc, act );
      var bp = Math.max( anc, act );
      s.SetAnchorPos( jumpDown ? tp : bp );
    }
    // または、もとの "キャレット位置" を範囲選択の基点にする
    else { s.SetAnchorPos( act ); }
    // 下の行へジャンプしたとき、ジャンプ先の行全体を選択範囲に含める
    if ( jumpDown && endOfBookmarkLine ) {
      s.EndOfLine( true, mePosLogical );
      ScrollX = 1;
    }
  }
  ScrollY = ( ScrollY === sy ) ? sy : yy;
}


// ---------- ▼ 関数 ▼ ---------- //
/**
 * 関数 MenuKey( str, maxStrLength, toWideWidth, blankChr )
 * ポップアップメニューに表示するラベルを生成する
 */
function MenuKey( str, menuWidth, toWideWidth, b1 ) {
  var keyWidth = ( /^[\s ]*[\s!-~\u200A\u2216\u22A0\u25AF]+$/.test( str ) )
               ? Math.floor( menuWidth *1.2 ) : menuWidth;
  var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
  var key = str ? ( regBlankLine.test( str ) ? "( 空白行 )" : str )
                : "( 空行 )";
  var regBlankChar = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g;
  key = key.replace( /^[\s ]+/, "" )
           .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " \u203A " ) //「 › 」
           .slice( 0, keyWidth + 1 )
           .replace( /&/g, "&&" )
        // .replace( /\\/g, "\u2216" )          //「∖」
           .replace( regBlankChar, "\u25AF" );  //「▯」
  // 半角英小文字と ascii記号を全角化
  if ( toWideWidth === 2 ) {
    key = key.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
    } );
  }
  // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (\u200A) を付加
  else if ( toWideWidth === 1 ) {
    key = key.replace( /[!-%'-.:-@\[-`{-~fijl\u00A5\u22A0\u25AF]|&&/g,
              "\u200A$&\u200A" )
             .replace( /\u200A+/g, "\u200A" )
             .replace( RegExp( b1 + "\u200A", "g" ), b1 );
    keyWidth += ( key.match( /[\u200A\u203A]|&&/g ) || "" ).length;
  }
  key = ( key.length > keyWidth )
      ? key.slice( 0, keyWidth ) + " ..." : key;
  return key;
}

/**
 * 関数 TimerElapsed( end, start )
 * start からの経過時間を [ s. sss 秒 ] で返す
 */
function TimerElapsed( end, start ) {
  var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
  return "  [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
}

/**
 * 関数 GetIniOptionNum( key )
 * 引数で指定された設定項目の「値」を返す(※数値のみ)
 */
function GetIniOptionNum( key ) {
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  // Mery.ini を探す
  var meryPath = editor.FullName;
  var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
  if ( ! Fso.FileExists( iniPath ) ) {
    var mery = Fso.GetBaseName( meryPath );
    iniPath = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
            + "\\Mery\\" + mery + ".ini";
  }
  // Mery.ini を読み込む
  var iniFile = Fso.OpenTextFile( iniPath, 1 );
  var iniText = iniFile.ReadAll();
  iniFile.Close();
  // 項目の値を取得する
  return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
}


include版


設定変更サブメニュー

分割サブメニュー
分割サブメニュー
  • ブックマークの件数が多いときはサブメニューに分割表示します。
初期値では 30 件超で分割サブメニューを表示する設定にしてありますが、モニターの高さに合わせて分割単位を変更することができます(設定変更サブメニューで変更可)。


※ スクリーンショット画像は開発中のサンプル画像です。
「メニューの再表示位置を調整する」コマンドは実装していません。

  • includeライブラリ」を使用し、設定内容は外部ファイルに保存します(変数 settingEnable で設定。デフォルト: 有効)。
  • あらかじめ includeライブラリ をインストールしてください。
  • 設定内容の保存場所は Mery\Macros\MacroSettings\<ブックマーク一覧ジャンプ>.json
    または %AppData%\Mery\MacroSettings\<ブックマーク一覧ジャンプ>.json です。
<ブックマーク一覧ジャンプ> の部分はこのマクロのファイル名
「▼ 通常版 設定項目 ▼」以降の設定項目は『初期値』としてのみ利用され、ソースコード内の設定項目を直接書き換えする必要はありません。
※ ただし、settingEnable 変数を完全に無効にする場合は、ソースコード内で変更する必要があります。
⇒ settingEnable を無効にした場合は「通常版」とほぼ同じ状態になり、「設定変更」サブメニューが表示されなくなります。


ソースコード
#title = "ブックマークジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#icon = "bookmark_list.ico"
#include "include/IO.js"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",243

/**
 * ---------------------------------------------------------
 * 「ブックマーク一覧ジャンプ」
 *   https://www.haijin-boys.com/wiki/ブックマーク一覧ジャンプ
 *   Original created by: Kuro & goat (2012/06/22 - 2012/09/24)
 * ---------------------------------------------------------
 *   Modified         by: sukemaru    (2018/08/08 - 2020/06/24)
 *  【include版】     by: sukemaru    (2019/04/15 - 2020/06/24)
 * ---------------------------------------------------------
 */

var start = new Date();		// 所要時間計測(開始)
var setting = {};

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

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

// ◆ JSON ファイルのベース名
var jsonName = ScriptName.replace( /\.js$/i, "" );	// 既定値

// 任意の名前に変更する場合はアンコメントして書き換える
// jsonName = "ブックマークジャンプ";


// ■ 連番の桁埋め(右寄せ/空白埋め)用空白文字の定義
var blankChr = " ";	// " " or "\u2002" or "\u3000" or "\u2007" or ...

  /* 半角数字の幅に等しい空白文字として
     MS UI Gothic では「2分アキ」 = EN SPACE: "\u2002"
     (MeiryoKe_UI Gothic は MS UI Gothic に同じ)
     Meiryo UI では「和字間隔」 = 全角空白: "\u3000"
     Segoe UI では「図形間隔」 = FIGURE SPACE: "\u2007"
     にすると具合がよさそうですが、ウエイトによって幅が変わるので... */


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

// 【include版】ではポップアップメニューから変更すること
setting.blockSelectEnable = false;
setting.keepInitialSelect = false;
setting.endOfBookmarkLine = false;
setting.autoLineModeEnable = false;
setting.lineColumnView = false;
setting.extraMenuEnable = true;
setting.menuPinEnable = true;
setting.menuScrollEnable = true;
setting.subMenuEnable = true;
setting.subMenuStyle = 0;
setting.subMenuHeight = 30;
setting.menuWidth = 55;
setting.toWideWidth = 0;
setting.menuPosMouse = true;

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


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

// ソースコードの「設定項目」内の初期値を保存する
var initialSettings = setting;
if ( initialSettings.settingEnable ) {
  // JSON ファイルから設定を読み込む
  jsonName = jsonName || ScriptName.replace( /\.js$/i, "" );
  setting  = IO.Deserialize( setting, jsonName );
  // 通常版の設定変数に再代入
  var settingEnable      = setting.settingEnable;
  var blockSelectEnable  = setting.blockSelectEnable;
  var keepInitialSelect  = setting.keepInitialSelect;
  var endOfBookmarkLine  = setting.endOfBookmarkLine;
  var extraMenuEnable    = setting.extraMenuEnable;
  var menuPinEnable      = setting.menuPinEnable;
  var menuScrollEnable   = setting.menuScrollEnable;
  var autoLineModeEnable = setting.autoLineModeEnable;
  var lineColumnView     = setting.lineColumnView;
  var subMenuEnable      = setting.subMenuEnable;
  var subMenuStyle       = setting.subMenuStyle;
  var subMenuHeight      = setting.subMenuHeight;
  var menuWidth          = setting.menuWidth;
  var toWideWidth        = setting.toWideWidth;
  var menuPosMouse       = setting.menuPosMouse;
  var mouseDllEnable     = setting.mouseDllEnable;
}
/* ▲ 【include版】用のコード ▲ */ 

// 連番の桁埋め(右寄せ/空白埋め)用
var b1 = ( ! blankChr || ( "" + blankChr ).length > 1 )
       ? " " : blankChr;
/**
 * Object.prototype.PadSpace( len, chr )
 * Object オブジェクトに拡張メソッドを追加(グローバル)
 * 数値/文字列の左側を chr で桁埋めした文字列をかえす
 */
Object.prototype.PadSpace = function(len, chr) {
  var dgt = String(this);
  len = Number(len) || dgt.length;
  chr = chr ? chr.toString() : b1;
  if (len < 0 || len < dgt.length || chr.length !== 1) return dgt;
  for (var i = 0; i < len; i++) chr += chr;
  return (chr + dgt).slice(- len);
};

// カーソルと選択範囲の位置を保存
var d = editor.ActiveDocument,  s = d.selection;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var l_ay  = s.GetActivePointY( mePosLogical );
var v_ay  = s.GetActivePointY( mePosView );
var sx = ScrollX,  sy = ScrollY;
// ブックマーク行の変数
var bmArray = [];
var bmY, bmStr, vy, ly, y;
// アクティブ行がブックマークされているか
var flag = 0,  isBookmarked = 0;

// ブックマーク行を検索
Redraw = false;
// 先頭行がブックマークされているか
s.SetActivePoint( mePosLogical, 1, 2 );
if ( s.PreviousBookmark() ) {
  ly = s.GetActivePointY( mePosLogical );
  vy = s.GetActivePointY( mePosView );
  if ( ly === l_ay ) { flag = 1;  isBookmarked = 1; }
  bmArray.push( { LY: ly,  VY: vy,  flag: flag } );
}
// 2行目以降のブックマークを探す
s.SetActivePos( 0 );
while ( s.NextBookmark() ) {
  ly = s.GetActivePointY( mePosLogical );
  vy = s.GetActivePointY( mePosView );
  if ( ly === l_ay ) { flag = 1;  isBookmarked = 1; }
  else { flag = 0; }
  bmArray.push( { LY: ly,  VY: vy,  flag: flag } );
}
// ブックマークの件数
var bmCount = bmArray.length;

// カーソル位置と選択範囲を復帰
s.SetActivePos( act );  s.SetAnchorPos( anc );
ScrollX = sx;  ScrollY = sy;
Redraw = true;

// ---------- ▼ ループ開始位置 ▼ ---------- //

do {
  // ループしたときはタイマーをリセット
  if ( y ) { start = new Date(); }

  // Mery.ini から「行の表示方法」を取得する
  if ( autoLineModeEnable ) {
    lineColumnView = GetIniOptionNum( "LineColumnView" );
  }
  var ay = lineColumnView ? v_ay : l_ay;
  // 全体の行数
  var lines = d.GetLines( lineColumnView ? meGetLineView : 0 );
  // ブックマーク行の文字列を取得する
  if ( bmCount ) {
    for ( var i = 0; i < bmCount; i ++ ) {
      bmY = lineColumnView ? bmArray[i].VY : bmArray[i].LY;
      bmStr = d.GetLine( bmY, lineColumnView ? meGetLineView : 0 );
      bmArray[i].id = bmY;
      bmArray[i].str = MenuKey( bmStr, menuWidth, toWideWidth, b1 );
    }
  }
  var numWidth = ( ( menuPinEnable || ! bmCount ) ? lines : bmY )
                 .toString().length;

  // ポップアップメニューの準備
  var bmMenu = CreatePopupMenu();

  // ステータスラベル
  var status1 = ( bmCount )
  ? " ブックマーク: "
    + bmCount.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
    + " 件 "
  : " ブックマークがありません。 ";
  var status2 = ( bmCount ? "/ " : "" )
  + "全体の行数: "
  + lines.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
  + ( lineColumnView ? " 行 (表示行)" : " 行 (論理行)" );

  // アクティブ行のチェックマークフラグ (meMenuChecked = 1)
  var Check = function( num ) { return ( num === ay ) *1; }

  // ピン止めアイテム
  var bmPin     = ay.PadSpace( numWidth ) + ": "
                + "ブックマークを設定/解除 (&B)";
  var countPin  = "".PadSpace( numWidth )
                + " ▼ " + status1 + " ▼";
  var cancelPin = "".PadSpace( numWidth )
                + " キャンセル\t& ";
  var topPin    = ( 1 ).PadSpace( numWidth ) + ": "
                + "** 先頭行へジャンプ (&T) **";
  var endPin    = lines.PadSpace( numWidth ) + ": "
                + "** 最終行へジャンプ (&E) **";
  var actPin    = ay.PadSpace( numWidth ) + ": "
                + "** 行頭へジャンプ (&A) **";

  // メニューの最上部に「設定/解除」をピン止め
  if ( bmCount || extraMenuEnable ) {
    bmMenu.Add( bmPin, 20000000, isBookmarked );
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( cancelPin, 0 );	// 「キャンセル」
    bmMenu.Add( "----", 0, meMenuSeparator );

    /* 【include版】の設定変更サブメニュー */ 
    if ( initialSettings.settingEnable ) {
      bmMenu.AddPopup( "".PadSpace( numWidth )
                       + " 設定を変更する (&S)"
                     , SettingsMenu( setting ) );
      bmMenu.Add( "----", 0, meMenuSeparator );
    }
  }

  // 「ブックマーク一覧」ポップアップメニュー
  if ( bmCount ) {
    bmMenu.Add( "----", 0, meMenuSeparator );
    // メニュー上部のピン止めアイテム
    if ( menuPinEnable
    && ( bmArray[0].id > 1 || ! isBookmarked && ay > 1 && ay < lines ) ) {
      if ( bmArray[0].id > 1 ) {
        bmMenu.Add( topPin, 1, Check( 1 ) );		// 「先頭行へジャンプ」
      }
      if ( ! isBookmarked && ay > 1 && ay < lines ) {
        bmMenu.Add( actPin, ay, meMenuChecked );	// 「行頭へジャンプ」
      }
      if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ].id !== lines ) {
        bmMenu.Add( endPin, lines, Check( lines ) );	// 「最終行へジャンプ」
      }
      bmMenu.Add( "----", 0, meMenuSeparator );
    }

    // 「分割サブメニュー」をピン止め
    if ( subMenuEnable && bmCount > subMenuHeight ) {
       DevidedMenu( bmMenu, bmArray, bmCount, numWidth, subMenuStyle, subMenuHeight, b1 );
    }

    // ブックマーク一覧
    bmMenu.Add( countPin, 0, 0 );	// ▼ ブックマーク: n 件 ▼
    for ( var i = 0, bm, num; i < bmCount; i ++ ) {
      if ( i % 10 === 0 && i > 0 ) {
        bmMenu.Add( "----", 0, meMenuSeparator );	// 10行ごとにセパレータ
        if ( menuScrollEnable && i % subMenuHeight === 0 ) {
          bmMenu.Add( cancelPin, 0 );	// 30行* ごとに「キャンセル」
          bmMenu.Add( "----", 0, meMenuSeparator );
        }
      }
      // ブックマーク行をポップアップメニューに追加
      bm  = bmArray[i];
      num = bm.id.PadSpace( numWidth ).replace( /\d$/, "&$&: " );
      bmMenu.Add( num + bm.str, bm.id, Check( bm.id ) );
    }

    // メニュー下部のピン止めアイテム
    if ( menuPinEnable && bmArray[ bmCount -1 ].id !== lines ) {
      bmMenu.Add( "----", 0, meMenuSeparator );
      bmMenu.Add( endPin, lines, Check( lines ) );	// 「最終行へジャンプ」
    }
    if ( menuScrollEnable && bmCount > subMenuHeight ) {
      bmMenu.Add( "----", 0, meMenuSeparator );
      bmMenu.Add( cancelPin, 0 );	// 「キャンセル」
    }
  }

  // 「ブックマークがありません」ポップアップメニュー
  else if ( extraMenuEnable ) {
    // 「ブックマークがありません」
    bmMenu.Add( "※ " + status1 + " ※", 0, meMenuGrayed );
    if ( ! menuPinEnable ) {
      bmMenu.Add( " " + status2, 0 );	// 全体の行数
    }
    // ピン止めアイテム
    if ( menuPinEnable ) {
      if ( lines > 1 ) {
        bmMenu.Add( "----", 0, meMenuSeparator );	
        bmMenu.Add( topPin, 1, Check( 1 ) );		// 「先頭行へジャンプ」
        if ( ay > 1 && ay < lines ) {
          bmMenu.Add( actPin, ay, meMenuChecked );	// 「行頭へジャンプ」
        }
        bmMenu.Add( endPin, lines, Check( lines ) );// 「最終行へジャンプ」
      }
      else {
        bmMenu.Add( actPin, ay, meMenuChecked );	// 「行頭へジャンプ」
      }
    }
  }

  // ステータスとポップアップメニューを表示
  Status = status1 + status2
         + TimerElapsed( new Date(), start );
  var y = bmMenu.Track( menuPosMouse );

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

// 設定変更した場合はメニューを再表示する
} while ( y >= 10000000 && y < 10000100 && ! menuPosMouse  );

// ---------- ▲ ループ ここまで ▲ ---------- //

// ブックマークを設定/解除
if ( y === 20000000 ) {
  editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}

// ジャンプ
else if ( y && y < 10000000 ) {
  s.SetActivePoint( lineColumnView ? mePosView : mePosLogical, 1, y );
  var yy = s.GetActivePointY( mePosView );

  // アクティブ行へのジャンプではスクロール位置をリセット
  if ( y === ay ) { ScrollY = yy }

  // ジャンプ前の選択範囲からジャンプ先の行まで範囲選択する
  if ( blockSelectEnable && act !== anc ) {
    var jumpDown = ( ay < y );
    // もとの選択範囲の文字列を含んだままにする
    if ( keepInitialSelect ) {
      var tp = Math.min( anc, act );
      var bp = Math.max( anc, act );
      s.SetAnchorPos( jumpDown ? tp : bp );
    }
    // または、もとの "キャレット位置" を範囲選択の基点にする
    else { s.SetAnchorPos( act ); }
    // 下の行へジャンプしたとき、ジャンプ先の行全体を選択範囲に含める
    if ( jumpDown && endOfBookmarkLine ) {
      s.EndOfLine( true, mePosLogical );	// ※ 表示行にも対応させるべきか?
      ScrollX = 1;	// 水平スクロールを左端にリセット
    }
  }
  ScrollY = ( ScrollY === sy ) ? sy : yy;
}


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

/**
 * 関数 MenuKey( str, maxStrLength, toWideWidth, blankChr )
 * ポップアップメニューに表示するラベルを生成する
 * 
 * ・行頭空白を除去、空白文字を圧縮
 * ・削られてしまう 「&」 を補完
 * ・「¥」(\u005C) を 「∖」(\u2216) に置換:     または 「╲」(\u2572), 「﹨」(\uFE68)
 * ・ゼロ幅や特殊な空白文字を豆腐に置換:    → 「⊠」(\u22A0) または 「▯」(\u25AF)
 * ・判別しづらい半角記号を全角に置換:      !"%'(),.:;@[]`{|}
 *     + 「a-z」 を全角に置換
 *   または半角記号の前後にスキマをつける:  HAIR SPACE 「 」(\u200A)
 * ・文字数を切り詰め
 */
function MenuKey( str, menuWidth, toWideWidth, b1 ) {
  // HAIR SPACE( ),「∖」「⊠」「▯」
  var keyWidth = ( /^[\s ]*[\s!-~\u200A\u2216\u22A0\u25AF]+$/.test( str ) )
               ? Math.floor( menuWidth *1.2 ) : menuWidth;
  var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
  var key = str ? ( regBlankLine.test( str ) ? "( 空白行 )" : str )
                : "( 空行 )";
  var regBlankChar = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g;
  key = key.replace( /^[\s ]+/, "" )
           .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " \u203A " ) //「 › 」
           .slice( 0, keyWidth + 1 )
           .replace( /&/g, "&&" )
           .replace( /\\/g, "\u2216" )          //「∖」
           .replace( regBlankChar, "\u25AF" );  //「▯」
  // 半角英小文字と ascii記号を全角化
  if ( toWideWidth === 2 ) {
    key = key.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
    } );
  }
  // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (\u200A) を付加
  else if ( toWideWidth === 1 ) {
    key = key.replace( /[!-%'-.:-@\[-`{-~fijl\u00A5\u22A0\u25AF]|&&/g,
              "\u200A$&\u200A" )	//「¥」「⊠」「▯」
             .replace( /\u200A+/g, "\u200A" )	// HAIR SPACE
             .replace( RegExp( b1 + "\u200A", "g" ), b1 );
    // HAIR SPACE,「›」
    keyWidth += ( key.match( /[\u200A\u203A]|&&/g ) || "" ).length;
  }
  key = ( key.length > keyWidth )
      ? key.slice( 0, keyWidth ) + " ..." : key;
  return key;
}

/**
 * 関数 TimerElapsed( end, start )
 * start からの経過時間を [ s. sss 秒 ] で返す
 */
function TimerElapsed( end, start ) {
  var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
  return "  [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
}

/**
 * 関数 GetIniOptionNum( key )
 * 引数で指定された設定項目の「値」を返す(※数値のみ)
 */
function GetIniOptionNum( key ) {
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  // Mery.ini を探す
  var meryPath = editor.FullName;
  var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
  if ( ! Fso.FileExists( iniPath ) ) {
    var mery = Fso.GetBaseName( meryPath );
    iniPath = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
            + "\\Mery\\" + mery + ".ini";
  }
  // Mery.ini を読み込む
  var iniFile = Fso.OpenTextFile( iniPath, 1 );
  var iniText = iniFile.ReadAll();
  iniFile.Close();
  // 項目の値を取得する
  return + RegExp( "^" + key + "=(\\d+)$", "m" ).exec( iniText )[1];
}

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

/**
 * 関数 DevidedMenu( objPopupMenu, itemsArray, itemsCount, numWidth, subMenuStyle, subMenuHeight, blankChr )
 * サブメニュー「※ 20* 件ずつ表示 ※  ▶」/「 1 - 20* 件目  ▶」に
 * 配列の「アイテム」を分割表示する
 * ※「 1 - 20 件目  ▶」の先頭にチェックマーク「*」をつけるために
 *   for() ループを2回まわす
 */
function DevidedMenu( objPopupMenu, bmArray, bmCount, numWidth, subMenuStyle, subMenuHeight, b1 ) { 
  b1 = ( b1.length === 1 ) ? b1 : " ";
  var devidedSubMenu = CreatePopupMenu();
  var indent = "".PadSpace( numWidth, b1 );
  var smArray = [];
  var tickedId;

  if ( subMenuStyle ) {
    // 「※ 20* 件ずつ表示 ※  ▶」をピン止め
    objPopupMenu.AddPopup( indent
    + " ※   " + subMenuHeight + " 件ずつに分割して表示 (&D)  ※"
    , devidedSubMenu );
    objPopupMenu.Add( "", 0, meMenuSeparator );
  }

  // 配列 bmArray のアイテムをサブメニューに追加していく
  bmArrayLoop:
  for ( var i = 0, j = 1, k = subMenuHeight, subMenu, line, num;
  i < bmCount; i ++, j ++, k ++ ) {
    if ( i % subMenuHeight === 0 ) {
      // smArray に「_from - _to 件目  ▶」用のサブメニューを生成する
      subMenu = CreatePopupMenu();
      smArray.push( {
        menu: subMenu,
        from: j,
        to: ( k < bmCount ) ? k : bmCount
      } );
    }

    // bmArray のアイテムをサブメニュー配下に追加する
    // ※ なぜか smArray[smArray.length -1].menu ではなく subMenu への Add() でよい
    line  = bmArray[i];
    num = line.id.PadSpace( numWidth, b1 ).replace( /\d$/, "&$&: " );
    subMenu.Add( num + line.str, line.id, line.flag );
    // アクティブ行のチェックマークフラグのついた行
    if ( line.flag === 1 ) { tickedId = smArray.length - 1; }

    // 10 件ごとにセパレータ、height ごとに「キャセル」行
    if ( j % 10 === 0 || j === bmCount) {
      subMenu.Add( "", 0, meMenuSeparator );
      if ( j % subMenuHeight === 0 || j === bmCount ) {
        subMenu.Add( indent + " キャンセル\t& ", 0 );
      }
    }
  }

  // 「_from - _to 件目  ▶」メニュー項目を親メニュー内に追加
  var popupMenu = subMenuStyle ? devidedSubMenu : objPopupMenu;
  var bmWidth   = bmCount.toString().length;
  var smIndent  = subMenuStyle ?  "" : indent;

  smArrayLoop:
  for ( var i = 0, smCount = smArray.length, tick, smLabel;
  i < smCount; i ++ ) {
    // ※ AddPopup に meMenuChecked は付けられないので文字「*」で代替
    tick = ( i === tickedId ) ? "* " : b1 + " ";
    smLabel = smArray[i].from.PadSpace( bmWidth, b1 ).replace( /\d/, "&$&" )
            + " - "
            + smArray[i].to.PadSpace( bmWidth, b1 ) + " 件目:";
    // ※ smArray[i].menu は PopupMenu オブジェクト
    popupMenu.AddPopup( smIndent + tick + smLabel, smArray[i].menu );

    // セパレータと「キャセル」行
    if ( ( i % subMenuHeight === 0 && i !== 0 ) || i === smCount - 1 ) {
      popupMenu.Add( "", 0, meMenuSeparator );
      if ( subMenuStyle ) {
        popupMenu.Add( " キャンセル\t& ", 0 );
      }
    }
    if ( i % 10 === 0 && i !== 0 ) {
      popupMenu.Add( "", 0, meMenuSeparator );
    }
  }
}

/**
 * 関数 SettingsMenu( objSettinds )
 * ポップアップメニューに「設定変更」サブメニューを表示する
 */
function SettingsMenu( setting ) {
  var ss = setting;
  var setMenu = CreatePopupMenu();
  // メニューのオプションフラグ
  // ※ meMenuChecked の数値は 1 なので hogeEnable *1 で代用できる
  // ※ meMenuGrayed の数値は 2 なので hogeEnable *2 で代用できる
  var grayFlag = ! ss.settingEnable ? meMenuGrayed : 0;
  var blockSelectGrayFlag = ! ss.blockSelectEnable *2 || grayFlag;
  var keepInitialSelectFlag = blockSelectGrayFlag
  + ( ss.keepInitialSelect && ss.blockSelectEnable ) *1;
  var endOfBookmarkLineFlag = blockSelectGrayFlag
  + ( ss.endOfBookmarkLine && ss.blockSelectEnable ) *1;
  var autoLineModeGrayFlag = ss.autoLineModeEnable *2 || grayFlag;
  var subMenuFlag = ! ss.subMenuEnable *2 || grayFlag;
  var maxHeightFlag = ( ss.subMenuHeight >= 100 ) *2 || subMenuFlag;
  var minHeightFlag = ( ss.subMenuHeight < 20 ) *2 || subMenuFlag;
  var maxWidthFlag = ( ss.menuWidth > 100  ) *2 || grayFlag;
  var minWidthFlag = ( ss.menuWidth < 30 ) *2 || grayFlag;

  // 「設定変更」サブメニューのアイテム	
  setMenu.Add( "  ジャンプ先の行まで 範囲選択する (&B)"
             , 10000001, ss.blockSelectEnable + grayFlag );
  setMenu.Add( "  もとの選択範囲を ジャンプ後の範囲選択に含める (&K)"
             , 10000002, keepInitialSelectFlag );
  setMenu.Add( "  下の行にジャンプしたときに 行全体を選択 (&E)"
             , 10000003, endOfBookmarkLineFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "  ブックマークがなくても メニューを表示する (&N)"
             , 10000004, ss.extraMenuEnable + grayFlag );
  setMenu.Add( "「先頭行/最終行/行頭 へジャンプ」 を表示する (&P)"
             , 10000005, ss.menuPinEnable + grayFlag );
  setMenu.Add( "  " + subMenuHeight
             + " 件ごとに 「キャンセル」 を表示する (&C)"
             , 10000006, ss.menuScrollEnable + grayFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "「行の表示方法」 を自動設定する (&A)"
             , 10000007, ss.autoLineModeEnable + grayFlag );
  setMenu.Add( "・ 行数を 「論理行」 で表示する"
             + ( ss.lineColumnView ? " (&L)" : "" )
             , 10000008, ! lineColumnView + autoLineModeGrayFlag );
  setMenu.Add( "・ 行数を 「表示行」 で表示する"
             + ( ss.lineColumnView ? "" : " (&V)" )
             , 10000008, lineColumnView + autoLineModeGrayFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "「分割サブメニュー」 を表示する (&D)"
             , 10000009, ss.subMenuEnable + grayFlag );
  setMenu.Add( "・ メインメニューの中に「 1 - " + ss.subMenuHeight
             + " 件目: \u25B6」 を表示する"
             + ( ss.subMenuStyle ? " (&T)" : "" )
             , 10000010, ! ss.subMenuStyle + subMenuFlag );
  setMenu.Add( "・ 「" + ss.subMenuHeight
             + " 件ずつに分割して表示 \u25B6」"
             + " の中に表示する" + ( ss.subMenuStyle ? "" : " (&T)" )
             , 10000010, ss.subMenuStyle + subMenuFlag );
  setMenu.Add( "  サブメニューの分割単位を 10行 増やす (&X) \t"
             + ss.subMenuHeight + ( ss.subMenuHeight >= 100 ? ""
             : " → " + ( ss.subMenuHeight + 10 ) )
             , 10000011, maxHeightFlag );
  setMenu.Add( "  サブメニューの分割単位を 10行 減らす (&Z) \t"
             + ss.subMenuHeight + ( ss.subMenuHeight < 20 ? ""
             : " → " + ( ss.subMenuHeight - 10 ) )
             , 10000012, minHeightFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "  メニューの表示幅を 10文字 増やす (&+)\t"
             + ss.menuWidth + ( ss.menuWidth > 100 ? ""
             : " → " + ( ss.menuWidth + 10 ) )
             , 10000013, maxWidthFlag );
  setMenu.Add( "  メニューの表示幅を 10文字 減らす (&-)\t"
             + ss.menuWidth + ( ss.menuWidth < 30 ? ""
             : " → " + ( ss.menuWidth - 10 ) )
             , 10000014, minWidthFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "・ 半角 a-z と記号を全角で表示する (&F)\t"
             , 10000015, ( ss.toWideWidth === 2 ) + grayFlag );
  setMenu.Add( "・ 半角英・記号の文字間隔を調整する (&W)\t"
             , 10000016, ( ss.toWideWidth === 1 ) + grayFlag );
  setMenu.Add( "・ 半角英数記号を半角のまま表示する (&H)\t"
             , 10000017, ! ss.toWideWidth + grayFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "・ 入力カーソル の位置 にメニューを表示する"
             + ( ss.menuPosMouse ? " (&M)" : "" )
             , 10000018, ! ss.menuPosMouse + grayFlag );
  setMenu.Add( "・ マウスポインタの位置 にメニューを表示する"
             + ( ss.menuPosMouse ? "" : " (&M)" )
             , 10000018, ss.menuPosMouse + grayFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "  設定内容をロックする (&S)"
             , 10000000, ! ss.settingEnable *1 );
  setMenu.Add( "", 0, meMenuSeparator );
  setMenu.Add( "「ジャンプ」マクロの JS ファイルを開く (&O)"
             , 10000100 );
  setMenu.Add( "「ジャンプ」マクロの JSON ファイルを開く (&J)"
             , 10000101 );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "  設定を初期化する (&I)", 10000102, grayFlag );
  setMenu.Add( "----", 0, meMenuSeparator );
  setMenu.Add( "  キャンセル\t& ", 0 );
  return setMenu;
}

/**
 * 関数 SettingsChange( num )
 * ポップアップメニューで選択した項目の設定状態を変更する
 */
function SettingsChange( num ) {
  var isChanged = true;
  switch ( num ) {
  case 10000001:	// ジャンプ先の行まで 範囲選択する
    blockSelectEnable = setting.blockSelectEnable
                      = ! blockSelectEnable;
    break;
  case 10000002:	// もとの選択範囲を ジャンプ後の範囲選択に含める
    keepInitialSelect = setting.keepInitialSelect
                      = ! keepInitialSelect;
    break;
  case 10000003:	// 下の行にジャンプしたときに 行全体を選択
    endOfBookmarkLine = setting.endOfBookmarkLine
                      = ! endOfBookmarkLine;
    break;
  case 10000004:	// ブックマークがなくても メニューを表示する
    extraMenuEnable = setting.extraMenuEnable
                    = ! extraMenuEnable;
    break;
  case 10000005:	// 「先頭行/最終行/行頭 へジャンプ」 を表示する
    menuPinEnable = setting.menuPinEnable
                  = ! menuPinEnable;
    break;
  case 10000006:	// 20 件* ごとに 「キャンセル」 を表示する
    menuScrollEnable = setting.menuScrollEnable
                     = ! menuScrollEnable;
    break;
  case 10000007:	// 「行の表示方法」 を自動設定する
    autoLineModeEnable = setting.autoLineModeEnable
                       = ! autoLineModeEnable;
    break;
  case 10000008:	// 行数を 「論理行/表示行」 で表示する
    lineColumnView = setting.lineColumnView
                   = ! lineColumnView;
    break;
  case 10000009:	// 「分割サブメニュー」 を表示する
    subMenuEnable = setting.subMenuEnable
                  = ! subMenuEnable;
    break;
  case 10000010:	// 「20* 件ずつに分割して表示 ▶」のなかに表示する
    subMenuStyle = setting.subMenuStyle
                 = Number( ! subMenuStyle );
    break;
  case 10000011:	// サブメニューの分割単位を 10行 増やす
    subMenuHeight = setting.subMenuHeight += 10;
    break;
  case 10000012:	// サブメニューの分割単位を 10行 減らす
    subMenuHeight = setting.subMenuHeight -= 10;
    break;
  case 10000013:	// メニューの表示幅を 10文字 増やす
    menuWidth = setting.menuWidth += 10;
    break;
  case 10000014:	// メニューの表示幅を 10文字 減らす
    menuWidth = setting.menuWidth -= 10;
    break;
  case 10000015:	// 半角 a-z と記号を全角で表示する
    toWideWidth = setting.toWideWidth = 2;
    break;
  case 10000016:	// 半角英・記号の文字間隔を調整する
    toWideWidth = setting.toWideWidth = 1;
    break;
  case 10000017:	// 半角英数記号を半角のまま表示する
    toWideWidth = setting.toWideWidth = 0;
    break;
  case 10000018:	// 入力カーソル/マウスポインタ の位置 にメニューを表示する
    menuPosMouse = setting.menuPosMouse
                 = ! menuPosMouse;
    break;
  case 10000000:	// 設定内容をロックする
    settingEnable = setting.settingEnable
                  = ! settingEnable;
    break;
  case 10000100:	// 「ジャンプ」マクロの JS ファイルを開く
    isChanged = false;
    Status = " " + ScriptFullName;
    new ActiveXObject( "WScript.Shell" )
    .Run( '"' + editor.FullName + '" "' + ScriptFullName + '"' );
    break;
  case 10000101:	// 「ジャンプ」マクロの JSON ファイルを開く
    isChanged = false;
    OpenJumpJson( jsonName, decode = false, toWideWidth );
    break;
  case 10000102:	// 設定を初期化する
    isChanged = false;
    CheckJsonFile( jsonName, decode = false, toWideWidth );
    break;
  default:
    sIsChanged = false;
    break;
  }
  if ( isChanged ) {
    IO.Serialize( setting, jsonName );
    Status = "  設定の変更を保存しました。";
  }
}

/**
 * 関数 OpenJumpJson( setting, jsonName )
 * JSON ファイルを開く
 */
function OpenJumpJson( jsonName, decode, toWideWidth ) {
  IO.Serialize( setting, jsonName );
  Sleep( 500 );
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  if ( IO.Path.IsExist( jsonPath )
  && ( json = JsonContents( jsonPath, decode, toWideWidth ) ).length ) {
    var confirmStr = "設定ファイルは正常です \n\n"
                   + json + "設定ファイルを開きますか? ";
    if ( Confirm( confirmStr ) ) {
      new ActiveXObject( "WScript.Shell" )
      .Run( '"' + editor.FullName + '" "' + jsonPath + '"' );
    }
  }
  else {
    Alert( "設定ファイルがありません \n" + jsonDir + "  " );
  }
}

/** 
 * 関数 CheckJsonFile( jsonName )
 * JSON ファイルの初期化/実在確認
 */
function CheckJsonFile( jsonName, decode, toWideWidth ) {
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  var confirmStr = jsonPath + "  \n\n"
                 + "設定ファイルを初期化しますか? "
  if ( Confirm( confirmStr ) ) {
    IO.Serialize( initialSettings, jsonName );
    Sleep( 500 );
    var msg = ( IO.Path.IsExist( jsonPath )
    && ( json = JsonContents( jsonPath, decode, toWideWidth ) ).length )
    ? "設定ファイルは正常です \n\n" + json
    : "設定ファイルがありません \n" + jsonDir + "  ";
    Alert( msg );
  }
}

/** 
 * 関数 JsonDir()
 * JSON ファイルの親フォルダのパス
 */
function JsonDir() {
  var jsonDir;
  if ( IO.Path.IsExist(
  editor.FullName.replace( /\.exe$/i, ".ini" ) ) ) {
    jsonDir = editor.FullName.replace( /[^\\]+$/i, "" )
            + "Macros\\MacroSettings";
  }
  else {
    jsonDir = new ActiveXObject( "WScript.Shell" )
              .ExpandEnvironmentStrings( "%APPDATA%" )
            + "\\Mery\\MacroSettings";
  }
  return jsonDir;
}

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