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

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
sukemaru版(通常版/include版)を増補改訂
MSY-07 (トーク | 投稿記録)
変数の宣言を追加
 
(2人の利用者による、間の13版が非表示)
1行目: 1行目:
 
== 概要 ==
= goat 版 =
 
ポップアップメニューでジャンプ先を選択。範囲指定中はジャンプ先まで選択範囲を拡大します。
ポップアップメニューでジャンプ先を選択。範囲指定中はジャンプ先まで選択範囲を拡大します。
Mery Ver.1.1.2.2840 および Ver.2.0.9.3936 での動作を確認しています。
(2012.09.24)
<source lang="javascript">
#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;
})()
</source>
== Mery ver 2.7.0 以降への対応 ==
<span style="color:#c00;"> goat 版を '''Mery ver 2.7.0 以降'''で使用する場合は、'''20''' 行目付近を以下のように書き換えてください。</span><br>
変更しない場合、ドキュメントの 1 行目がブックマークされていてもポップアップメニューに表示されなくなります。 (2019/04/16 sukemaru)
; 変更前
18.    var bookmarks = new Array();
19.    <span style="color:#c00;">StartOfDocument(false);</span>
20.    <i style="color:#408080;">// 先頭行がブックマークされてないか</i>
21.    var isTopMarked = false;
22.    <span style="color:#c00;">CharRight(false);</span>
23.    if(PreviousBookmark()){
24.      isTopMarked = true;
; 変更後
18.    var bookmarks = new Array();
19.    <span style="color:#c00;">'''//''' StartOfDocument(false);</span>
20.    <i style="color:#408080;">// 先頭行がブックマークされてないか</i>
21.    var isTopMarked = false;
22.    <b style="color:#c00;">SetActivePoint(mePosLogical, 1, 2);</b>
23.    if(PreviousBookmark()){
24.      isTopMarked = true;
= sukemaru 版 =
goat 版を元にして、ポップアップメニューを表示するまでの速度を改善し、動作設定をカスタマイズできるようにしました。
<br>
;▼ goat 版からの変更点 ▼
* ソースコード内の設定項目から "表示行" / "論理行" の選択可(初期値は "論理行")
* 設定項目で "ジャンプ先までの範囲選択" はしない状態を初期値にした
* ブックマーク行の検索 ~ ポップアップメニューの表示 までの速度を改善
* ポップアップメニューの体裁を変更(「[[ポップアップメニューで検索先にジャンプ#sukemaru_版|検索ジャンプ]]」マクロにあわせた)
* ステータスバーにブックマーク件数などの情報を表示
* 「ブックマークがありません」メニュー。
* ジャンプしたときのスクロール位置を調整。
* ジャンプ先まで範囲選択するときの先頭/末尾を調整。
* 「先頭行/最終行 へジャンプ」をメニューにピン止め表示。
* 「ブックマークを設定/解除」をメニューの先頭にピン止め表示。
* ポップアップメニューだと読み取りづらい半角英小文字・と ascii 記号の一部を全角で表示。
<br>
[[ファイル:Mery_ブックマークジャンプ(通常版)_SS.png|frameless|640px|thumb|submenuenable = 2]]
<br clear=all>
: Mery でプログラミング用のフォントを使っている人だと、ポップアップメニュー内で半角 <q>'''¥'''</q> 記号 (U+005C) が'''バックスラッシュ''' (U+005C) にならないのは気落ち悪いかも? ということで、ソースコード内の関数 MenuKey() のコードのコメントアウトしてある行を有効化すると "擬似的に" '''バックスラッシュ'''化できます <br> (※ <q>'''∖'''</q> (U+2216) に置換して表示します)。
== ダウンロード ==
'''ダウンロード:''' 「[[ファイル:ブックマークジャンプ.zip]]」(アイコン入り) 
<br> 最終更新: 2019/12/05(Mery 2.7.0 以降への対応と [[#include版|include版]] を追加)
: オマケとして [ 編集 ] メニューのブックマーク関連コマンドのアイコン化用マクロ×4


== ソースコード ==
== ソースコード ==
<syntaxhighlight lang="javascript" copy>
#title="ブックマーク一覧"
/*
* ブックマーク一覧をポップアップメニューにして選択ジャンプ
* Mery標準のブックマークが対象
* 範囲選択中の場合は選択範囲を拡大
*/
(function(){
// 描画停止
Redraw = false;
var sel = document.selection;
var flgBlock = !sel.IsEmpty;
//カーソル位置の保存
var activePos = sel.GetActivePos();
var anchorPos = sel.GetAnchorPos();
var sX = ScrollX;
var sY = ScrollY;


* このマクロではポップアップメニューの表示に EN SPACE <q> </q> (U+2002) などを使用します。ファイルに保存するさいは、文字コードを shift_JIS にしないでください('''UTF-8''' や Unicode で保存する)。
var bookmarks = [];
<source lang="javascript" style="height:80em; overflow:auto;" highlight="28-60">
var menuKey = "";
#title = "ブックマーク一覧ジャンプ"
// 先頭行がブックマークされてないか
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
var isTopMarked = false;
#icon = "bookmark_list.ico"
sel.SetActivePoint(mePosLogical, 1, 2);
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",243
if(sel.PreviousBookmark()){
 
isTopMarked = true;
/**
sel.SelectLine();
* ---------------------------------------------------------
menuKey = sel.Text.slice(0,24).replace(/\t/g, "\\t");
* 「ブックマーク一覧ジャンプ」
sel.Collapse();
*  Orginal created by: Kuro, goat (2012/06/22 - 2012/09/24)
bookmarks.push("Line " + sel.GetActivePointY(mePosLogical) + ":\t" + menuKey);
*  Modified by:       sukemaru  (2018/08/08 - 2019/12/05)
} else {
* ---------------------------------------------------------
sel.StartOfDocument(false);
* ブックマーク一覧をポップアップメニューで表示し、選択した行へジャンプする。
}
*
while(sel.NextBookmark()){
* ・ 行番号は "表示行" / "論理行" の設定可。
sel.SelectLine();
* ・ ブックマーク行の検索 ~ ポップアップメニュー表示 の速度を改善。
menuKey = sel.Text.slice(0, 24).replace(/\t/g, "\\t");
* ・ ポップアップメニューの体裁を変更。
sel.Collapse();
* ・ ステータスバーに情報を表示。
bookmarks.push("Line " + sel.GetActivePointY(mePosLogical) + ":\t" + menuKey);
* ・「ブックマークがありません」メニュー。
}
* ・ ジャンプしたときのスクロール位置を調整。
var bmcount = bookmarks.length;
* ・ ジャンプ先まで範囲選択するときの先頭/末尾を調整。
if(bmcount == 0){
* ・「先頭行/行頭/最終行 へジャンプ」をメニューにピン止め表示
//カーソル位置の復帰
* ・「ブックマークを設定/解除」をメニューの先頭にピン止め表示
sel.SetActivePos(activePos);
*
sel.SetAnchorPos(anchorPos);
*/
ScrollX = sX;
 
ScrollY = sY;
var start = new Date(); // 所要時間計測(開始)
} else {
 
var BookmarkMenu = CreatePopupMenu();
// ---------- ▼ 設定項目 ▼ ---------- //
for(var i = 0; i < bmcount; i++){
 
//メニューのアクセスキーも1から始まるほうが便利
// ■ ジャンプする前に選択範囲があったときはジャンプ先の行まで範囲選択する?
BookmarkMenu.Add("&" + (i+1) + " " + bookmarks[i], i+1);
var blockSelectEnable = false; // (true 範囲選択する / false 範囲選択しない)
}
 
var ret = BookmarkMenu.Track(0);
    // ■ もとの選択範囲をジャンプ後の範囲選択に含める?
if(ret == 0){
    var keepInitialSelect = false; // (true 含める / false 含めない)
//カーソル位置の復帰
 
sel.SetActivePos(activePos);
    // ■ 下の行にジャンプしたとき、ジャンプ先の行全体(論理行)を選択範囲に含める?
sel.SetAnchorPos(anchorPos);
    var endOfBookmarkLine = false; // (true 含める / false 含めない)
ScrollX = sX;
 
ScrollY = sY;
// ■ 行番号の表示方法を Mery.ini から「自動」で読み込む?
} else {
var autoLineModeEnable = false; // (true 自動読み込み / false 手動設定)
sel.StartOfDocument(false);
 
if(isTopMarked){
    // ■ 行番号の表示方法(手動設定用)
ret--;
    var lineColumnView = 0; // ( 0 論理行 / 1 表示行 )
}
 
for(i = 0; i < ret; i++){
// ■ 「ブックマークがありません」メニューを表示する?
sel.NextBookmark();
var extraMenuEnable = true; // (true 表示する / false 表示しない)
}
 
}
// ■ ポップアップメニューに「先頭行/最終行 へジャンプ」をピン止め表示する?
}
var menuPinEnable = true; // (true 表示する / false 表示しない)
if(flgBlock){
 
//ジャンプ前の選択開始位置からジャンプ後のカーソル位置まで範囲選択
// ■ ポップアップメニューに表示する文字数の目安
sel.SetAnchorPos(anchorPos);
var menuWidth = 65; // (全角/半角の区別なし)
}
 
// 描画再開
// ■ 半角英文字を全角で表示する [!"%'(),.:;@\[\]`a-z{|}]
Redraw = true;
var toFullWidth = true; // (true 置換する / false 置換しない)
})();
 
</syntaxhighlight>
// ■ ポップアップメニューを表示する位置
var menuPosMouse = true; // ( true マウス位置 / false カーソル位置 )
 
// ---------- ▲ 設定項目 ▲ ---------- //
 
// Mery.ini から「行の表示方法」を取得する( 表示行 = 1 / 論理行 = 0 )
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 linesWidth = lines.toString().length;
// カーソルと選択範囲の位置を保存
var s = d.selection;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var aY = s.GetActivePointY( posMode );
var sX = ScrollX,  sY = ScrollY;
// ブックマーク行の変数
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行目以降のブックマークを探す
s.SetActivePos( 0 );
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();
// アクティブ行のチェックマーク (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 ) {
  bmMenu.Add( bmPin, 20000000, isBookmarked );
  bmMenu.Add( "-----", 0, meMenuSeparator );
}
 
// 「ブックマーク一覧」ポップアップメニュー
if ( bmCount ) {
  // メニュー上部のピン止めアイテム
  bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
  bmMenu.Add( "-----", 0, meMenuSeparator );
  if ( menuPinEnable && bmArray[0][1] > 1 ) {
    bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
  }
  if ( ! isBookmarked && aY > 1 && aY < lines ) {
    bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
  }
  bmMenu.Add( "-----", 0, meMenuSeparator );
  bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
  // ブックマーク行をポップアップメニューに追加
  for ( var i = 0, flags; i < bmCount; i ++ ) {
    if ( i != 0 && i % 10 == 0 ) {
      bmMenu.Add( "-----", 0, meMenuSeparator ); // 10行ごとにセパレータ
    }
    bmMenu.Add( bmArray[i][0], bmArray[i][1], Check( bmArray[i][1] ) );
  }
  // メニュー下部のピン止めアイテム
  if ( menuPinEnable && bmArray[ bmCount - 1 ][1] !== lines ) {
    bmMenu.Add( "-----", 0, meMenuSeparator );
    bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
  }
}
 
// 「ブックマークがありません」ポップアップメニュー
else if ( extraMenuEnable ) {
  bmMenu.Add( "※" + status1 + "& ※", 0 );
  if ( ! menuPinEnable ) {
    bmMenu.Add( status2 + "& ", 0 );
  }
  // ピン止めアイテム
  else 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 if ( lines == 1 ) {
    bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
  }
}
 
// ステータスバーとポップアップメニューを表示
Status = status1 + status2 + TimerStatus( new Date(), start );
var y = bmMenu.Track( menuPosMouse );
 
// ブックマークを設定/解除
if ( y == 20000000 ) {
  editor.ExecuteCommandByID( MEID_EDIT_TOGGLE_BOOKMARK = 2126 );
}
// ジャンプ
else if ( y > 0 ) {
  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;
}
 
// ---------- ▼ 関数 ▼ ---------- //
 
/**
* 関数 MenuKey( str, num )
* ポップアップメニューに表示するラベルを生成する
*
* ・行頭空白を除去、空白文字を圧縮
* ・「¥」(U+005C) を「∖」に置換: 「∖」(U+2216) または 「╲」(U+2572) 「﹨」(U+FE68)
* ・「&」 を補完
* ・「a-z」 と判別しづらいメタ文字を全角に置換  →  条件つきに変更
* ・文字数を切り詰め
* ・行番号をケタ埋め: EN SPACE 「 」(U+2002)
*/
function MenuKey( str, num ) {
  var menuKey = ( str ) ? /^[\t  ]+$/.test( str ) ? "( 空白行 )" : str
                        : "( 空行 )";
  menuKey = menuKey.replace( /^[\t  ]+/, "" )
                  .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                  .slice( 0, menuWidth *2 )
                // .replace( /[\\]/g, "∖" )
                  .replace( /&/g, "&&" );
  if ( toFullWidth ) {
    menuKey = menuKey.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g, function( tmp ) {
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
    } );
  }
  menuKey = ( menuKey.length > menuWidth )
          ? menuKey.slice( 0, menuWidth ) + " ..." : menuKey;
  return ( "          &" + num ).slice( - linesWidth - 1 ) + ":  " + menuKey;
}
 
/**
* 関数 TimerStatus( end, start )
* start からの経過時間計測
* [ s. sss 秒 ] で返す
*/
function TimerStatus( 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 mery    = Fso.GetBaseName( meryPath );
  var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
  if ( ! Fso.FileExists( iniPath ) ) {
    var WshShell = new ActiveXObject( "WScript.Shell" );
    iniPath = WshShell.SpecialFolders( "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];
}
 
/**
* ---------- ▼ 更新履歴 ▼ ----------
* 2019/03/29:
* ・sukemaru版をマクロライブラリに投稿。
* 2019/04/08:
* ・Quit() の削除と、軽微な変更。
* 2019/04/16:
* ・Mery 2.7.0 でのブックマークの仕様変更に対応。【include版】を追加。
* 2019/12/05:
* ・「ブックマークを設定/解除」 をメニューに追加
* ・メニュー内にブックマーク件数を表示
* ・「メニューを表示する位置」 の設定を追加
* ・「もとの選択範囲をジャンプ後の範囲選択に含める」 を設定項目に追加
* ・【include版】を大幅に変更。
*/
</source>
 
 
== include版 ==
 
*[[ダウンロード|ZIP 書庫]]内の「'''include版'''」フォルダの JS ファイルを使用すると、「[[ポップアップメニューで検索先にジャンプ#include版|ポップアップメニューで検索先にジャンプ]]」マクロと同様に、<span style="color:#c00;">マクロの動作設定の変更をポップアップメニュー内の項目のチェック ON/OFF でできるようになります。 </span>
<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|設定変更サブメニュー]]
<br clear=all><br>
[[ファイル:Mery_ブックマークジャンプ_SS(2).png|frameless|254px|thumb|right|分割サブメニュー]]
*ブックマークの件数が多いときはサブメニューに分割表示します。
:初期値では 20 件超で分割サブメニューを表示する設定にしてありますが、モニターの高さに合わせて分割単位を変更することができます(設定変更サブメニューで変更可)。
<br clear=all><br>
 
*[[includeライブラリ]] を使用し、設定内容は外部ファイルに保存します(◆settingEnable 変数で設定。デフォルト: 有効)。<br>
<div id="注1" class="warningbox">
* あらかじめ [[includeライブラリ]] をインストールしてください。
* 設定内容の保存場所は '''Mery\Macros\MacroSettings\<ブックマーク一覧ジャンプ>.json''' <br> または '''%AppData%\Mery\MacroSettings\<ジャンプ>.json''' です。<br> (※ <ブックマーク一覧ジャンプ> の部分はこのマクロのファイル名)
</div>
: 「▼ 通常版 設定項目 ▼」以降の設定項目は『初期値』としてのみ利用され、ソースコード内の設定項目を直接書き換えする必要はありません。
: ※ ただし、settingEnable 変数を完全に無効にする場合は、ソースコード内で変更する必要があります。<br> → settingEnable を無効にした場合は「通常版」と同じ状態になり、「設定変更」サブメニューが表示されなくなります。
 
 
<source lang="javascript" style="height:80em; overflow:auto;">
#title = "ブックマークジャンプ"
#tooltip = "ポップアップメニューでブックマーク行にジャンプ"
#include "include/IO.js"
#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 - 2019/12/05)
*  【include 版】                  (2019/04/15 - 2019/12/05)
* ---------------------------------------------------------
* 【include 版】
* ・「設定変更」サブメニューを表示
* ・ 設定内容を外部ファイル(JSON)に保存
* ・ ブックマーク件数が多いときはサブメニューに分割表示
*
*    設定ファイルの保存場所は
*      Mery\Macros\MacroSettings\<jsonName>.json
*    または
*      %AppData%\Mery\MacroSettings\<jsonName>.json
*    ※ <jsonName> の部分はこのマクロのファイル名(設定項目で変更可)
*/
 
var start = new Date(); // 所要時間計測(開始)
 
var setting = {};
// ---------- ▼ 【include版】 初期設定項目 ▼ ---------- //
 
// ◆ 「設定変更」サブメニューを表示するか?
setting.settingEnable = true; // (true する / false しない)
 
// ◆ JSON ファイルのベース名
var jsonName = ScriptName.replace( /\.js$/i, "" ); // 既定値
 
// 任意の名前に変更する場合はアンコメントして書き換える
// jsonName = "ブックマーク一覧ジャンプ";
 
// ---------- ▼ 通常版 設定項目 ▼ ---------- //
// 【include版】ではポップアップメニューから変更すること
 
setting.blockSelectEnable = false;
setting.keepInitialSelect = false;
setting.endOfBookmarkLine = false;
setting.autoLineModeEnable = false;
setting.lineColumnView = 0; // ( 0 論理行 / 1 表示行 )
setting.extraMenuEnable = true;
setting.menuPinEnable = true;
setting.menuScrollEnable = true; // スペースキーでスクロール
setting.subMenuEnable = true; // 分割サブメニュー
setting.subMenuHeight = 20; // 初期値 = 20; (20 件* ずつに分割)
setting.menuWidth = 55; // (30-100 程度 ※半角文字だけの行では×2)
setting.toFullWidth = false; // [!"%'(),.:;@\[\]`a-z{|}]
setting.menuPosMouse = true; // ( true マウス位置 / false カーソル位置 )
 
// ---------- ▲ 設定項目 ▲ ---------- //
 
 
// menuWidth = ( menuWidth < 30 )  ? 25
//          : ( menuWidth > 100 ) ? 105
//                                : menuWidth;
 
// ソースコードの「設定項目」内の初期値を保存する
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 subMenuHeight = setting.subMenuHeight;
  var menuWidth = setting.menuWidth;
  var toFullWidth = setting.toFullWidth;
  var menuPosMouse = setting.menuPosMouse;
}
 
do {
  if ( y ) { start = new Date(); } // ループしたときはタイマーをリセット
 
  // 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 linesWidth = lines.toString().length;
  // カーソルと選択範囲の位置を保存
  var s = d.selection;
  var act = s.GetActivePos(),  anc = s.GetAnchorPos();
  var aY = s.GetActivePointY( posMode );
  var sX = ScrollX, sY = ScrollY;
  // ブックマーク行の変数
  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行目以降のブックマークを探す
  s.SetActivePos( 0 );
  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();
 
  // 「ブックマーク一覧」ポップアップメニュー
  // または「ブックマークがありません」ポップアップメニュー
  BookmarkMenu( bmMenu, bmArray, aY );
 
  // ステータスバーとポップアップメニューを表示
  Status = status1 + status2
        + 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 )
          + ":  ブックマークを設定/解除 (&B)";
  var countPin = MenuIndent()
              + " ▼ " + status1.slice( 0, -1 ) + " ▼";
  var cancelPin = MenuIndent()
              + "  キャンセル\t& ";
  var topPin = MenuIndent( 1, linesWidth )
            + ":  ** 先頭行へジャンプ (&T) **";
  var endPin = MenuIndent( lines, linesWidth )
            + ":  ** 最終行へジャンプ (&E) **";
  var actPin = MenuIndent( aY, linesWidth )
            + ":    行頭へジャンプ (&A)";
 
  // メニューの最上部に「設定/解除」をピン止め
  if ( bmCount || extraMenuEnable ) {
    bmMenu.Add( bmPin, 20000000, isBookmarked );
    bmMenu.Add( "----", 0, meMenuSeparator );
 
    /* 【include版】の設定変更サブメニュー */
    if ( initialSettings.settingEnable ) {
      SettingsMenu( bmMenu );
    }
  }
 
  // 「ブックマーク一覧」ポップアップメニュー
  if ( bmCount ) {
  // メニュー上部のピン止めアイテム
    bmMenu.Add( cancelPin, 0 ); // 「キャンセル」
    bmMenu.Add( "----", 0, meMenuSeparator );
    bmMenu.Add( "----", 0, meMenuSeparator );
    // メニュー上部のピン止めアイテム
    if ( menuPinEnable && ( bmArray[0][1] > 1
        || ! isBookmarked && aY > 1 && aY < lines ) ) {
      if ( bmArray[0][1] > 1 ) {
        bmMenu.Add( topPin, 1, Check( 1 ) ); // 「先頭行へジャンプ」
      }
      if ( ! isBookmarked && aY > 1 && aY < lines ) {
        bmMenu.Add( actPin, aY, meMenuChecked ); // 「行頭へジャンプ」
      }
      if ( bmCount > subMenuHeight && bmArray[ bmCount -1 ][1] !== lines ) {
        bmMenu.Add( endPin, lines, Check( lines ) ); // 「最終行へジャンプ」
      }
      bmMenu.Add( "----", 0, meMenuSeparator );
    }
 
    // 「分割サブメニュー」をピン止め
    if ( subMenuEnable && bmCount > subMenuHeight ) {
      var subMenu = DevidedSubMenuBM( bmMenu, bmArray );
    }
 
    // ブックマーク一覧
    bmMenu.Add( countPin, 0, 0 ); // ▼ ブックマーク: n 件 ▼
    for ( var i = 0; i < bmCount; i ++ ) {
      if ( i % 10 == 0 && i > 0 ) {
        bmMenu.Add( "----", 0, meMenuSeparator ); // 10行ごとにセパレータ
        if ( menuScrollEnable && i % subMenuHeight == 0 ) {
          bmMenu.Add( cancelPin, 0 ); // 20行* ごとに「キャンセル」
          bmMenu.Add( "----", 0, meMenuSeparator );
        }
      }
      // ブックマーク行をポップアップメニューに追加
      bmMenu.Add( bmArray[i][0], bmArray[i][1], Check( bmArray[i][1] ) );
    }
 
    // メニュー下部のピン止めアイテム
    if ( menuPinEnable && bmArray[ bmCount -1 ][1] !== 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( "----", 0, meMenuSeparator );
    // ステータスラベルをピン止め
    bmMenu.Add( "※ " + status1 + "  ※\t& ", 0 ); // 「ブックマークがありません」
    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 ); // 「行頭へジャンプ」
      }
    }
  }
}
 
/**
* 関数 MenuIndent( str )
* メニューラベルの字下げ
*/
function MenuIndent( str ) {
  str = str || "";
  var appendix = /^&\d/.test( str ) ? 1 : 0;
  return ( "          " + str ).slice( - linesWidth - appendix );
}
 
/**
* 関数 MenuKey( str, num )
* ポップアップメニューに表示するラベルを生成する
*
* ・行頭空白を除去、空白文字を圧縮
* ・「&」 を補完
* ・「¥」(U+005C) を 「∖」(U+2216) に置換:    または 「╲」(U+2572), 「﹨」(U+FE68)
* ・ゼロ幅や特殊な空白文字を豆腐に置換: → 「▯」(U+25AF) または 「⊠」(U+22A0)
* ・判別しづらい半角記号を全角に置換: !"%'(),.:;@[]`{|}
*    + 「a-z」 を全角に置換
*  または半角記号の前後にスキマをつける: HAIR SPACE 「 」(U+200A)
* ・文字数を切り詰め
* ・行番号を空白でケタ埋め: EN SPACE 「 」(U+2002)
*/
function MenuKey( str, num ) {
  var keyWidth = /^[\s ]*[\s!-~∖▯⊠ ]+$/.test( str ) ? menuWidth * 2 : menuWidth;
  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 menuKey = ( str ) ? regBlankLine.test( str ) ? "( 空白行 )" : str
                        : "( 空行 )";
  menuKey = menuKey.replace( /^[\t  ]+/, "" )
                  .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                  .slice( 0, keyWidth + 1 )
                  .replace( /[&]/g, "&&" )
                  .replace( /[\\]/g, "∖" )
                  .replace( regBlank, "▯" );
  if ( toFullWidth ) {
    menuKey = menuKey.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
      function( tmp ) {
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
      } );
  }
  else {
    // スラッシュ 以外の ascii 記号と fijl に HAIR SPACE (U+200A) を付加
    menuKey = menuKey.replace( /[!-%'-.:-@\[-`{-~fijl¥⊠▯]|&&/g, " $& " )
                    .replace( /\u200A+/g, " " )
                    .replace( /\u2002\u200A/g, " " );
    keyWidth = keyWidth
            + ( menuKey.match( /[\u200A›↲]|&&/g ) || "" ).length;
  }
  menuKey = ( menuKey.length > keyWidth )
          ? menuKey.slice( 0, keyWidth ) + " ..."
          : menuKey;
  num = MenuIndent( "&" + num ) + ": ";
  return num + menuKey;
}
 
/**
* 関数 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 mery    = Fso.GetBaseName( meryPath );
  var iniPath  = meryPath.replace( /\.exe$/i, ".ini" );
  if ( ! Fso.FileExists( iniPath ) ) {
    var WshShell = new ActiveXObject( "WScript.Shell" );
    iniPath = WshShell.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];
}
 
/**
* 関数 DevidedSubMenuBM( objPopupMenu, items )
* サブメニュー「※ 20* 件ずつ表示 ※  ▶」/「1 - 20* 件目  ▶」に
* 配列の「アイテム」を分割表示する
* ※「20*」の部分の数値は設定用変数 subMenuHeight で指定
*/
function DevidedSubMenuBM( objPopupMenu, items ) {
  var len      = items.length;
  var lenWidth = len.toString().length;
  var smRow    = Math.ceil( len / subMenuHeight );
  var smSq    = subMenuHeight * subMenuHeight;
  var smArray  = []; // SubMenu Array
  var smLabelArray = []; // SubMenu-Label Array
  var smId,  _from,  _to,  tick,  ticked;
 
  var subMenu  = CreatePopupMenu();
  var popupMenu = ( subMenuEnable == 1 )
                ? subMenu : objPopupMenu;
  if ( subMenuEnable == 1 ) {
    // 「※ 20* 件ずつ表示 ※  ▶」をピン止め
    objPopupMenu.AddPopup( MenuIndent() + " ※   "
                        + subMenuHeight + " 件ずつに分割して表示 (&D)  ※"
                        , subMenu );
    objPopupMenu.Add( "", 0, meMenuSeparator );
  }
 
  // サブメニューと配列のアイテムをポップアップメニューに追加していく
  for ( var i = 0; i < len; i ++ ) {
    // セパレータと「キャンセル」
    if ( i % subMenuHeight == 0 ) {
      if ( smRow > 10 && i != 0 && i % ( subMenuHeight * 10 ) == 0 ) {
        popupMenu.Add( "", 0, meMenuSeparator );
        if ( len > smSq && i % smSq == 0 ) {
          popupMenu.Add( MenuIndent() + "  キャンセル\t& ", 0 );
          popupMenu.Add( "", 0, meMenuSeparator );
        }
      }
 
      // 配列 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 件目」サブメニュー配下に
    // ※ smArray[smId] は CreatePopupMenu オブジェクト
    smArray[ smId ].Add( items[i][0], items[i][1], items[i][2] );
    // アクティブ行のフラグのついた行
    if ( items[i][2] ) { ticked = smId; }
 
    // 10 行ごとにセパレータ、さいごに「キャセル」行
    if ( ( i + 1 ) % 10 == 0  || i == len - 1) {
      smArray[ smId ].Add( "", 0, meMenuSeparator );
      if ( ( i + 1 ) % subMenuHeight == 0 || i == len - 1 ) {
        smArray[ smId ].Add( MenuIndent() + "  キャンセル\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;
}
 
 
// ---------- ▼ 【include版】 関数 ▼ ---------- //
 
/**
* 関数 SettingsMenu( objPopupMenu )
* ポップアップメニューに「設定変更」サブメニューを表示する
* 引数: メインスコープのポップアップメニューオブジェクト
*/
function SettingsMenu( objMenu ) {
  var subMenu = CreatePopupMenu();
  // メニューのオプションフラグ
  var grayFlag  = ! settingEnable ? meMenuGrayed : 0;
  var grayFlag1 = ( ! blockSelectEnable || ! settingEnable )
                ?  meMenuGrayed : 0;
  var keepInitialSelectFlag = ( keepInitialSelect && blockSelectEnable )
                            ? meMenuChecked : 0;
  var endOfBookmarkLineFlag = ( endOfBookmarkLine && blockSelectEnable )
                            ? meMenuChecked : 0;
  var grayFlag2 = ( autoLineModeEnable || ! settingEnable )
                ?  meMenuGrayed : 0;
  var maxHeightFlag = ( ! settingEnable || ! subMenuEnable || subMenuHeight >= 100 )
                          ? meMenuGrayed : 0;
  var minHeightFlag = ( ! settingEnable || ! subMenuEnable || subMenuHeight < 20 )
                          ? meMenuGrayed : 0;
  var maxWidthFlag = menuWidth > 100 ? meMenuGrayed : 0;
  var minWidthFlag = menuWidth < 30 ? meMenuGrayed : 0;
 
  // 「設定変更」サブメニューのアイテム
  objMenu.AddPopup( MenuIndent() + "  設定を変更する (&S)", subMenu );
  objMenu.Add( "----", 0, meMenuSeparator );
 
  subMenu.Add( "  ジャンプ先の行まで 範囲選択する (&B)",
              10000001, blockSelectEnable + grayFlag );
  subMenu.Add( "  もとの選択範囲を ジャンプ後の範囲選択に含める (&K)",
              10000002, keepInitialSelectFlag + grayFlag1 );
  subMenu.Add( "  下の行にジャンプしたときに 行全体を選択 (&E)",
              10000003, endOfBookmarkLineFlag + grayFlag1 );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  ブックマークがなくても メニューを表示する (&N)",
              10000004, extraMenuEnable + grayFlag );
  subMenu.Add( "「先頭行/最終行/行頭 へジャンプ」 を表示する (&P)",
              10000005, menuPinEnable + grayFlag );
  subMenu.Add( "  " + subMenuHeight + " 件ごとに 「キャンセル」 を表示する (&C)",
              10000012, menuScrollEnable + grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "「行の表示方法」 を自動設定する (&A)",
              10000006, autoLineModeEnable + grayFlag );
  subMenu.Add( "  行数を 「論理行」 で表示する (&L)",
              10000007, !lineColumnView + grayFlag2 );
  subMenu.Add( "  行数を 「表示行」 で表示する (&V)",
              10000007, lineColumnView + grayFlag2 );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "「分割サブメニュー」 を表示する (&D)"
            , 10000013, subMenuEnable + grayFlag );
  subMenu.Add( "  サブメニューの分割単位を 10行 増やす (&X) \t"
            + subMenuHeight
            + ( subMenuHeight >= 100 ? "" : " → " + ( subMenuHeight + 10 ) )
            , 10000014, maxHeightFlag );
  subMenu.Add( "  サブメニューの分割単位を 10行 減らす (&Z) \t"
            + subMenuHeight
            + ( subMenuHeight < 20 ? "" : " → " + ( subMenuHeight - 10 ) )
            , 10000015, minHeightFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  メニューの表示幅を 10文字 増やす (&+)\t"
            + menuWidth
            + ( menuWidth > 100 ? "" : " → " + ( menuWidth + 10 ) ),
              10000008, maxWidthFlag + grayFlag );
  subMenu.Add( "  メニューの表示幅を 10文字 減らす (&-)\t"
            + menuWidth
            + ( menuWidth < 30 ? "" : " → " + ( menuWidth - 10 ) ),
              10000009, minWidthFlag + grayFlag );
  subMenu.Add( "  半角 a-z を全角で表示する (&F)",
              10000010, toFullWidth + grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  入力カーソル の位置 にメニューを表示する"
            + ( menuPosMouse ? " (&M)" : "" ),
              10000011, !menuPosMouse + grayFlag );
  subMenu.Add( "  マウスポインタの位置 にメニューを表示する"
            + ( menuPosMouse ? "" : " (&M)" ),
              10000011, menuPosMouse + grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  設定内容をロックする (&S)", 10000000, !settingEnable*1 );
  subMenu.Add( "", 0, meMenuSeparator );
  subMenu.Add( "「ジャンプ」マクロの JS ファイルを開く (&O)", 10000016 );
  subMenu.Add( "「ジャンプ」マクロの JSON ファイルを開く (&J)", 10000017 );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  設定を初期化する (&I)", 10000018, grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  キャンセル\t& ", 0 );
}
 
/**
* 関数 SettingsChange( num )
* ポップアップメニューで選択した項目の設定状態を変更する
* ※ 設定変更でのメニュー再表示 do - while ループのさいに
*    JSON の再読みこみを省略するために
*    ローカル変数 = JSON 項目 = 設定値  の形式で記述する
*/
function SettingsChange( num ) {
  // var jsonPath = JsonDir() + "\\" + jsonName + ".json";
  var sIsChanged = true;
  switch ( num ) {
    case 10000000: // 設定内容をロックする
      settingEnable = setting.settingEnable
                    = ! settingEnable;
      break;
    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: // 「行の表示方法」 を自動設定する
      autoLineModeEnable = setting.autoLineModeEnable
                        = ! autoLineModeEnable;
      break;
    case 10000007: // 行数を 「論理行/表示行」 で表示する
      lineColumnView = setting.lineColumnView
                    = ! lineColumnView;
      break;
    case 10000008: // メニューの表示幅を 10文字 増やす
      menuWidth = setting.menuWidth += 10;
      break;
    case 10000009: // メニューの表示幅を 10文字 減らす
      menuWidth = setting.menuWidth -= 10;
      break;
    case 10000010: // 半角英文字を全角で表示する
      toFullWidth = setting.toFullWidth
                  = ! toFullWidth;
      break;
    case 10000011: // 入力カーソル/マウスポインタ の位置 にメニューを表示する
      menuPosMouse = setting.menuPosMouse
                  = ! menuPosMouse;
      break;
    case 10000012: // 20 件* ごとに 「キャンセル」 を表示する
      menuScrollEnable = setting.menuScrollEnable
                      = ! menuScrollEnable;
      break;
    case 10000013: // 「分割サブメニュー」 を表示する
      subMenuEnable = setting.subMenuEnable
                    = ! subMenuEnable;
      break;
    case 10000014: // サブメニューの分割単位を 10行 増やす
      subMenuHeight = setting.subMenuHeight += 10;
      break;
    case 10000015: // サブメニューの分割単位を 10行 減らす
      subMenuHeight = setting.subMenuHeight -= 10;
      break;
    case 10000016: // 「ジャンプ」マクロの JS ファイルを開く
      sIsChanged = false;
      Status = " " + ScriptFullName;
      OpenJumpJS( "setting.settingEnable = " );
      break;
    case 10000017: // 「ジャンプ」マクロの JSON ファイルを開く
      sIsChanged = false;
      OpenJumpJson( jsonName );
      break;
    case 10000018: // 設定を初期化する
      sIsChanged = false;
      CheckJsonFile( jsonName );
      break;
    default:
      sIsChanged = false;
      break;
  }
  if ( sIsChanged ) {
    IO.Serialize( setting, jsonName );
    Status = " 設定の変更を保存しました。";
  }
}
 
 
/**
* 関数 OpenJumpJS( str )
* このマクロの 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 ファイルを開く
*/
function OpenJumpJson( jsonName ) {
  IO.Serialize( setting, jsonName );
  Sleep( 500 );
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  if ( IO.Path.IsExist( jsonPath )
      && JsonContents( jsonPath ).length ) {
    var confirmStr = "設定ファイルは正常です \n\n"
                  + JsonContents( jsonPath )
                  + "設定ファイルを開きますか? ";
    if ( Confirm( confirmStr ) ) {
      var WshShell = new ActiveXObject( "WScript.Shell" );
      WshShell.Run( '"' + editor.FullName + '" "' + jsonPath + '"' );
    }
  } else {
    Alert( "設定ファイルがありません \n"
        + jsonDir + "  " );
  }
}
 
/**
* 関数 CheckJsonFile( jsonName )
* JSON ファイルの初期化/実在確認
*/
function CheckJsonFile( jsonName ) {
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  var confirmStr = jsonPath + "  \n\n"
                + "設定ファイルを初期化しますか? "
  if ( Confirm( confirmStr ) ) {
    IO.Serialize( initialSettings, jsonName );
    Sleep( 500 );
    var alertStr = ( IO.Path.IsExist( jsonPath )
                    && JsonContents( jsonPath ).length )
                ? "設定ファイルは正常です \n\n"
                  + JsonContents( jsonPath )
                : "設定ファイルがありません \n"
                  + jsonDir + "  ";
    Alert( alertStr );
  }
}
 
/**
* 関数 JsonDir()
* JSON ファイルの親フォルダのパス
*/
function JsonDir() {
  var jsonDir;
  if ( IO.Path.IsExist( editor.FullName.replace( /\.exe$/i, ".ini" ) ) ) {
    jsonDir = editor.FullName.replace( /[^\\]+$/i, "" )
            + "Macros\\MacroSettings";
  } else {
    var WshShell = new ActiveXObject( "WScript.Shell" );
    jsonDir = WshShell.ExpandEnvironmentStrings( "%APPDATA%" )
            + "\\Mery\\MacroSettings";
  }
  return jsonDir;
}
 
/**
* 関数 JsonContents( jsonPath [, bool] )
* JSON ファイルの文字列をメッセージボックス用に整形する
*
* 第1引数は JSON ファイルのパス
* 第2引数は真偽値(省略可、true なら \uHHHH をデコードする)
*/
function JsonContents( jsonPath, bool ) {
  var contents = ( jsonPath + "  \n"
  + IO.LoadFromFile( jsonPath )
      .replace( /^\{/, "\n{\n  " )
      .replace( /\}$/g, "\n}\n\n" )
      .replace( /,"/g, " ,\n  \"" )
      .replace( /":/g, "\": " )
  );
  if ( bool ) {
    // 「テキスト整形」マクロより >> 符号化/復号化 >> \uHHHH デコード
    var Decode_uHHHH = function( str ) {
      return str.replace( /\\u([0-9A-Fa-f]{4})/g, function( s, n ) {
        return String.fromCharCode( Number( "0x" + n ) );
      } );
    };
    contents = Decode_uHHHH( contents );
  }
  if ( toFullWidth ) {
    // 半角アルファベットの小文字を全角にするなら
    contents = contents.replace( /[a-z]/g,
      function( tmp ) {
        return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
      } );
  }
  return contents;
}
 
 
 
/**
* ---------- ▼ 更新履歴 ▼ ----------
* 2019/03/29:
* ・sukemaru版をマクロライブラリに投稿。
*
* 2019/04/08:
* ・Quit() の削除と、軽微な変更。
*
* 2019/04/16:
* ・Mery 2.7.0 でのブックマークの仕様変更に対応。
* ・【include版】を追加。
*
* 2019/12/05:
* ・「ブックマークを設定/解除」 をメニューに追加
* ・メニュー内にブックマーク件数を表示
* ・「もとの選択範囲をジャンプ後の範囲選択に含める」 を設定項目に追加
*
*  【include版】
* ・ポップアップメニュー生成コードを関数セクションに移動
* ・「分割サブメニュー」 を追加
* ・20* 行ごとに 「キャンセル」 を追加(スペースキーでスクロール)
*  「キャンセル」 行の追加単位は 「分割サブメニュー」 の分割設定にあわせた
* ・「設定変更」 したときのメニュー表示のループ処理を追加
* ・「半角 a-z を全角表示する」 を設定項目に追加
* ・その他、設定項目の追加、動作コードの変更
*/
</source>

2025年11月25日 (火) 16:53時点における最新版

概要[編集]

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

ソースコード[編集]

#title="ブックマーク一覧"
/*
* ブックマーク一覧をポップアップメニューにして選択ジャンプ
* Mery標準のブックマークが対象
* 範囲選択中の場合は選択範囲を拡大
*/
(function(){
	// 描画停止
	Redraw = false;
	var sel = document.selection;
	var flgBlock = !sel.IsEmpty;
	//カーソル位置の保存
	var activePos = sel.GetActivePos();
	var anchorPos = sel.GetAnchorPos();
	var sX = ScrollX;
	var sY = ScrollY;

	var bookmarks = [];
	var menuKey = "";
	// 先頭行がブックマークされてないか
	var isTopMarked = false;
	sel.SetActivePoint(mePosLogical, 1, 2);
	if(sel.PreviousBookmark()){
		isTopMarked = true;
		sel.SelectLine();
		menuKey = sel.Text.slice(0,24).replace(/\t/g, "\\t");
		sel.Collapse();
		bookmarks.push("Line " + sel.GetActivePointY(mePosLogical) + ":\t" + menuKey);
	} else {
		sel.StartOfDocument(false);
	}
	while(sel.NextBookmark()){
		sel.SelectLine();
		menuKey = sel.Text.slice(0, 24).replace(/\t/g, "\\t");
		sel.Collapse();
		bookmarks.push("Line " + sel.GetActivePointY(mePosLogical) + ":\t" + menuKey);
	}
	var bmcount = bookmarks.length;
	if(bmcount == 0){
		//カーソル位置の復帰
		sel.SetActivePos(activePos);
		sel.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){
			//カーソル位置の復帰
			sel.SetActivePos(activePos);
			sel.SetAnchorPos(anchorPos);
			ScrollX = sX;
			ScrollY = sY;
		} else {
			sel.StartOfDocument(false);
			if(isTopMarked){
				ret--;
			}
			for(i = 0; i < ret; i++){
				sel.NextBookmark();
			}
		}
	}
	if(flgBlock){
		//ジャンプ前の選択開始位置からジャンプ後のカーソル位置まで範囲選択
		sel.SetAnchorPos(anchorPos);
	}
	// 描画再開
	Redraw = true;
})();
スポンサーリンク