「位置情報を保存してから「すべて選択/選択解除」(非スクロール)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
第3版。「【include 版】位置を復帰/保存」を追加
MSY-07 (トーク | 投稿記録)
空行と改行の除去
 
(2人の利用者による、間の5版が非表示)
1行目: 1行目:
== 【include 版】すべて選択/選択解除 (非スクロール) ==
「'''すべて選択''' (Ctrl+A)」を実行して全文コピーやステータスバーで文書全体の文字数・行数などを確認したときにキャレットやスクロール位置がスッ飛んでいってしまったり、'''選択範囲を解除''' したときにも同様のことが起こったりするので、状況によってはスクロール位置とキャレット位置を元に戻す手間が面倒ですよね…。


「すべて選択 (Ctrl+A)」を実行してステータスバーで文書全体の文字数・行数などを確認したいときにキャレットやスクロール位置がスッ飛んでいってしまったり、選択範囲を解除したときにも同様のことが起こったりしてしまったりするので、状況によってはスクロール位置とキャレット位置を元に戻す手間が面倒です…。
== ダウンロード ==
;>> 「[[ファイル:【include 版】すべて選択/選択解除.zip]] (アイコン入り)」


* 2019/10/21: 【include 版】の初版
* 2019/10/27: 【include 版】の第2版(描画速度を微妙に改善)
* 2019/11/13: 【include 版】の第3版
:* 「[[#【include 版】位置を復帰/保存|位置を復帰/保存]]」マクロを追加
:* マクロ追加により既存マクロのコードを微修正
:* JSON ファイル名の既定値を変更 「すべて選択」 → 「位置情報を保存」
* 2020/11/01: 【include 版】の第4版
:* リストに保存する各ファイルの情報を オブジェクト.プロパティ 形式に変更 (※ 以前のバージョンでの JSON ファイルと互換性なし)
:* Mery Ver 3.0.1 以降のマルチカーソル選択範囲の保存/復帰可 (※ ウインドウの「分割」状態には非対応)


== 【include 版】すべて選択/選択解除 (非スクロール) ==
以下のふたつのマクロを使って「すべて選択」/「選択範囲を解除」すると、無用なスクロールやキャレット移動がなくなります。<br>  
以下のふたつのマクロを使って「すべて選択」/「選択範囲を解除」すると、無用なスクロールやキャレット移動がなくなります。<br>  
また、<span style="color:#0000c0;">ふたつのマクロを交互に実行することで「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えができます。</span>
また、<span style="color:#0000c0;">ふたつのマクロを交互に実行することで「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えができます ('''マルチカーソルに対応''')。</span>
 


お好みでツールバー(マクロバー)アイコンに登録するか、キーボードショートカットに割りあててご利用下さい。<br>  
お好みでツールバー(マクロバー)アイコンに登録するか、キーボードショートカットに割りあててご利用下さい。<br>  
※ すでに [[キーアサイン集]] の「[[キーアサイン集#すべて選択 (非スクロール)|すべて選択 (非スクロール)]]」「[[キーアサイン集#選択範囲を解除 (非スクロール)|選択範囲を解除 (非スクロール)]]」マクロを導入している場合は、当マクロのソースコードで上書き保存するのがよいとおもいます。
※ すでに [[キーアサイン集]] の「[[キーアサイン集#すべて選択 (非スクロール)|すべて選択 (非スクロール)]]」「[[キーアサイン集#選択範囲を解除 (非スクロール)|選択範囲を解除 (非スクロール)]]」マクロを導入している場合は、当マクロのソースコードで上書き保存するのがよいとおもいます。


<div id="すべて選択">
<div id="すべて選択">
;【include版】 すべて選択 (非スクロール)</div>
;【include版】 すべて選択 (非スクロール)</div>
:*「すべて選択」を実行する前のキャレット位置とスクロール位置を保存してから「[[キーアサイン集#すべて選択 (非スクロール)|すべて選択 (非スクロール)]]」を実行します。<br> ※ 「すべて選択」前に選択範囲があった場合は、選択範囲の開始/終了位置を保存します。
:*「すべて選択」を実行する前のキャレット位置とスクロール位置を保存してから「[[キーアサイン集#すべて選択 (非スクロール)|すべて選択 (非スクロール)]]」を実行します「すべて選択」前に選択範囲があった場合は、選択範囲の開始/終了位置を保存します。
:* 開いているタブごとに位置情報を保存し、すでに閉じられたタブの情報は逐次削除します。
:* 開いているタブごとに位置情報を保存し、すでに閉じられたタブの情報は逐次削除します。
:*「'''無題-<n>'''」タブの情報は <span style="background:#bfdfff;">ファイル名 = "無題"</span> として保存します。<br><span style="color:#c00;">※ 「選択解除」するまえに別の「無題-<m>」タブでこのマクロを実行すると "無題" の位置情報は上書きされます。</span>
:*「'''無題-<n>'''」タブの情報は <span style="background:#bfdfff;">ファイル名 = <code>"無題"</code></span> として保存します。<br><span style="color:#c00;">※ 複数の「無題」のタブの位置情報を個別に保存することはできません。<br>※ 「選択解除」するまえに別の「無題-<m>」タブでこのマクロを実行すると "無題" の位置情報は上書きされます。</span>
:*「すべて選択」状態からこのマクロを再実行した場合は、保存された位置情報・選択範囲を復帰します。(2020/11/01) <br> ※ この場合、保存されている位置情報・選択範囲を削除しません。


<div id="選択解除">
<div id="選択解除">
;【include版】 選択範囲を解除 (非スクロール)</div>
;【include版】 選択範囲を解除 (非スクロール)</div>
:*「すべて選択」の状態で実行したときのみ、「【include版】 すべて選択 (非スクロール)」マクロが保存した情報を利用して、キャレット位置とスクロール位置を復元します。<br> ※ 保存されている当該タブの情報は、このマクロの実行時に削除されます。
:*「すべて選択」の状態で実行したときのみ、「【include版】 すべて選択 (非スクロール)」マクロが保存した情報を利用して、キャレット位置とスクロール位置を復元します。<br> <span style="color:#0000c0;"> ※ 保存されている当該タブの位置情報は、このマクロの実行時に削除されます。<br>※「すべて選択」状態を解除したときに復元された選択範囲は、このマクロをもう一度実行すると完全に解除されます。</span>
:*「【include版】 すべて選択 (非スクロール)」マクロが保存した位置情報がない場合は「[[キーアサイン集#選択範囲を解除 (非スクロール)|選択範囲を解除 (非スクロール)]]」を実行します。
:*「【include版】 すべて選択 (非スクロール)」マクロが<span style="color:#0000c0;">保存した位置情報がない場合は「[[キーアサイン集#選択範囲を解除 (非スクロール)|選択範囲を解除 (非スクロール)]]」を実行します。</span>
:*<span style="color:#0000c0;"> ※「すべて選択」状態を解除したときに復元された選択範囲は、このマクロをもう一度実行すると完全に解除されます。</span>
:*ホイールスクロールなどによりキャレットが表示領域内にない状態、かつ「選択範囲なし」の状態で実行したときは、キャレットのある行まで画面をスクロールします。
:*ホイールスクロールなどによりキャレットが表示領域内にない状態、かつ「選択範囲なし」の状態で実行したときは、キャレットのある行まで画面をスクロールします。
<br>
:* 「マルチカーソル・複数選択範囲」の状態からこのマクロを連続で実行した場合 … (2020/11/01) <br> 1回目:各選択範囲のアクティブ側に各カーソルを残す(ゼロ幅のマルチカーソル)。<br> 2回目:マルチカーソルを解除する(カーソルを1つだけにする)。<br> ※ このマクロには、Mery Ver 3.0.0 以降の <kbd>Esc</kbd> キーによる「マルチカーソルの解除」と同等の機能(複数選択範囲からひとつの選択範囲だけを残す)を <u>含めていません</u>。
<div class="warningbox">
<div class="warningbox">
* このページのマクロは、「[[includeライブラリ]]」を利用し、外部ファイル(JSON)に情報を保存/参照します。<br> あらかじめ「includeライブラリ」を Macros フォルダに配置してください。
* このページのマクロは、「[[includeライブラリ]]」を利用し、外部ファイル(JSON)に情報を保存/参照します。<br> あらかじめ「includeライブラリ」を Macros フォルダに配置してください。
31行目: 40行目:
</div>
</div>


:* JSON ファイルには、アクティブなタブの 「ファイルパス」 「全文字数」 「選択範囲の開始/終了位置」 「スクロール位置」 「行番号」 を保存します。<br> 複数のタブで「すべて選択」を実行している場合は、それぞれのタブの情報が保存されます。
:* JSON ファイルには、アクティブなタブの 「ファイルパス」 「全文字数」 「範囲選択モード」 「選択範囲の開始/終了位置」 「マルチカーソル選択範囲」 「スクロール位置」 「アクティブ行番号」 を保存します。<br> 複数のタブで「すべて選択」を実行した場合は、それぞれのタブの情報が保存されます。
:* JSON ファイルへのファイルアクセスが最小限になる仕様にしてあります。<br>また、「すべて選択」を実行したときに他のタブで開かれていないファイルの情報があれば、それらのファイル情報は逐次削除するので、JSON ファイルが肥大化することはありません。
:* JSON ファイルへのファイルアクセスが最小限になる仕様にしてあります。<br>また、「すべて選択」で位置情報を保存するときに、JSON ファイルに「他のタブで開かれていないファイルの位置情報」があれば、それらのファイル情報は逐次削除するので、JSON ファイルが肥大化することはありません。
 


※ [[#【include 版】位置を復帰/保存|選択範囲(キャレット位置)を保存/復帰するためのマクロ]] を追加しました。
※ [[#【include 版】位置を復帰/保存|選択範囲(キャレット位置)を保存/復帰するためのマクロ]] を追加しました。
:* 「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えのさいに保存した位置情報を破棄せず、繰り返して「位置を復帰」の操作ができるようになります。
:* 「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えのさいに保存した位置情報を破棄せず、繰り返して「位置を復帰」の操作ができるようになります。
== ダウンロード ==
>> 「[[ファイル:【include 版】すべて選択/選択解除.zip]] (アイコン入り)」
* 2019/10/21: 【include 版】の第1版
* 2019/10/27: 【include 版】の第2版(描画速度を微妙に改善)
* 2019/11/13: 【include 版】の第3版
:* 「[[#【include 版】位置を復帰/保存|位置を復帰/保存]]」マクロを追加
:* マクロ追加により既存マクロのコードを微修正
:* JSON ファイル名の既定値を変更 「すべて選択」 → 「位置情報を保存」


== ソースコード ==
== ソースコード ==
=== 【include版】 すべて選択 (非スクロール) ===
=== 【include版】 すべて選択 (非スクロール) ===
<source lang="javascript" style="height:60em; overflow:auto;">
<syntaxhighlight lang="javascript" style="height:60em; overflow:auto;">
#title = "すべて選択 (位置を保存・非スクロール)"
#title = "すべて選択 (位置を保存・非スクロール)"
#tooltip = "位置情報を保存してから すべて選択 (スクロールしない)"
#tooltip = "位置情報を保存してから すべて選択 (スクロールしない)"
#include "include/IO.js"
#include "include/IO.js"
#icon = "select_all.ico"
// #icon = "select_all.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",111
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",111


63行目: 58行目:


/**
/**
  * sukemaru, 2019/10/21 - 2019/11/13 【include 版】
  * ---------------------------------------------------------
* 【include版】 すべて選択 (非スクロール)
*  sukemaru, 2019/10/21 - 2020/11/01
* ---------------------------------------------------------
  * 要:include ライブラリ
  * 要:include ライブラリ
  *  
  *  
  * ・「すべて選択」 前の選択範囲(キャレット位置)とスクロール位置などの
  * ・「すべて選択」前の選択範囲(キャレット位置)とスクロール位置などの
  *  情報を JSON ファイルに書き出す。
  *  情報を JSON ファイルに書き出す。
  *  → 「選択解除」 「位置を復帰」 マクロで、保存した位置情報に復元可。
  *  → 「選択解除」「位置を復帰」マクロで、保存した位置情報に復元可。
  * ※ すべて選択状態から「選択解除」マクロを実行(位置を復帰)すると、
* ・「すべて選択」状態から再実行すると「位置を復帰」(2020/11/01)
*
  * ※ すべて選択状態から「選択解除」マクロで「位置を復帰」すると、
  *    当該ファイルの位置情報は JSON から削除される。
  *    当該ファイルの位置情報は JSON から削除される。
  *  
  *  
89行目: 89行目:


var d = editor.ActiveDocument,  s = d.selection;
var d = editor.ActiveDocument,  s = d.selection;
var dText = d.Text,  dLength = dText.length;
var dPath = d.FullName || "無題";
var dLength = d.TextLength || d.Text.length;
var setting = { fileList: [] };
var list,  len;
var sMode = s.Mode || 0;
 
if ( ( s.TextLength || s.Text.length ) !== dLength ) {
  if ( sMode > 1 && ! d.ReadOnly ) { AddUndo(); }


if ( s.Text.length != dLength ) {
   /**
   /**
   * フルパス、文字数
   * フルパス (dPath), 文字数 (dLength)
   * 選択範囲の開始/終了位置(anc, act)
  * 範囲選択モード (mode)
   * スクロール位置(sx, sy)、アクティブ行(ay)
   * 選択範囲の開始/終了位置 (anc, act)
  * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
   */
  var dPath = d.FullName || "無題";
   var anc = s.GetAnchorPos(),  act = s.GetActivePos();
   var anc = s.GetAnchorPos(),  act = s.GetActivePos();
   var sx = ScrollX,  sy = ScrollY;
   var sx = ScrollX,  sy = ScrollY;
   var ay = s.GetActivePointY( mePosLogical );
   var ay = s.GetActivePointY( mePosLogical );
  /* マルチカーソル対応 */
  var sCount = s.Count || 0,  Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = { act: s.GetActivePos( i ),  anc: s.GetAnchorPos( i ) };
  }


   // すべて選択 (スクロールしない)
   // すべて選択 (スクロールしない)
   Redraw = false;
   // Redraw = false;
   s.SelectAll();
   s.SelectAll();
   ScrollX = sx;  ScrollY = sy;
   ScrollX = sx;  ScrollY = sy;
   Redraw = true;
   // Redraw = true;
 
   var eCount = Editors.Count,  docus,  dCount,  hit;
   var setting = { fileList: [] };
   setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
   setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
   var list = setting.fileList;
   list = setting.fileList;
   var infoExist = false;
   var infoExist = false;


  ListLoop: // ※ list.length はループ中に変動する
   for ( var i = 0, path; i < list.length; i ++ ) {
   for ( var i = 0, path; i < list.length; i ++ ) {
     path = list[i][0];
     path = list[i].path;
 
     // リストにファイルの情報があれば書き換える
     // リストにファイルの情報があれば書き換える
     if ( path == dPath ) {
     if ( path === dPath ) {
       infoExist = true;
       infoExist = true;
       list[i] = [ dPath, dLength, anc, act, sx, sy, ay ];
       list[i] = {
        path: dPath, len: dLength, mode: sMode,
        anc: anc, act: act, sel: Sel,
        sx: sx, sy: sy, ay: ay
      };
     }
     }
     // リストに現在開かれていないファイルの情報があれば削除する
     // リストに現在開かれていないファイルの情報があれば削除する
     else {
     else {
       var eCount = Editors.Count;
       DeleteLoop:
      var docus,  dCount,  filePath,  hit;
       for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
       for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
         docus = Editors.Item( ee ).Documents;
         docus = Editors.Item( ee ).Documents;
         dCount = docus.Count;
         dCount = docus.Count;
         for ( var dd = 0; dd < dCount; dd ++ ) {
         for ( var dd = 0; dd < dCount; dd ++ ) {
           filePath = docus.Item( dd ).FullName;
           if ( docus.Item( dd ).FullName === path ) { hit ++ }
          if ( path == filePath ) { hit ++ }
         }
         }
       }
       } // DeleteLoop
      // リストから削除し、ループ処理の i をひとつ巻き戻す
       if ( ! hit ) { list.splice( i --, 1 ) }
       if ( ! hit ) { list.splice( i --, 1 ) }
     }
     }
   }
   } // ListLoop


   // リストにファイルの情報がなければ追加する
   // リストにファイルの情報がなければ追加する
   if ( ! infoExist ) {
   if ( ! infoExist ) {
     list.push( [ dPath, dLength, anc, act, sx, sy, ay ] );
     list.push( {
      path : dPath, len: dLength, mode: sMode,
      anc: anc, act: act, sel: Sel,
      sx: sx, sy: sy, ay: ay
    } );
   }
   }


   setting.fileList = list;
   setting.fileList = list;
   IO.Serialize( setting, jsonName ); // JSON 書き込み
   IO.Serialize( setting, jsonName ); // JSON 書き込み
}
/* 「すべて選択」 の状態から位置を復帰する(位置情報を削除しない) */
else if ( dLength ) {
  setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
  list = setting.fileList;
  /**
  * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
  * フルパス (dPath), 文字数 (dLength)
  * 範囲選択モード (mode)
  * 選択範囲の開始/終了位置 (anc, act)
  * マルチカーソル選択範囲 (sel)
  * スクロール位置 (sx, sy), アクティブ行 (ay)
  */
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
    info = list[i];
    // リストにファイル情報があれば
    // 文書の文字数が同じなら、選択範囲(キャレット位置)を復元
    if ( info.path === dPath && info.len === dLength ) {
      // Redraw = false;
      s.SetActivePos( info.act );
      /* マルチカーソル選択範囲を復帰 */
      if ( ( sCount = info.sel.length ) > 0 ) {
        for ( var i = 0; i < sCount; i ++ ) {
          s.AddPos( info.sel[i].anc, info.sel[i].act );
        }
        s.AddPos( info.anc, info.act );
      }
      // 通常選択範囲または矩形選択範囲を復帰
      else {
        s.SetAnchorPos( info.anc );
        if ( info.mode === 2 ) { s.Mode = meModeBox; }
      }
      ScrollX = info.sx;  ScrollY = info.sy;
      // Redraw = true;
      break;
    }
  }
}
}


151行目: 207行目:
  * {"fileList":[]}
  * {"fileList":[]}
  */
  */
</source>
</syntaxhighlight>
 


=== 【include版】 選択範囲を解除 (非スクロール) ===
=== 【include版】 選択範囲を解除 (非スクロール) ===
<source lang="javascript" style="height:60em; overflow:auto;">
<syntaxhighlight lang="javascript" style="height:60em; overflow:auto;">
#title = "選択解除 (位置を復帰・非スクロール)"
#title = "選択解除 (位置を復帰・非スクロール)"
#tooltip = "範囲選択を解除 (スクロールしない) または 位置を復帰"
#tooltip = "範囲選択を解除 (スクロールしない) または 位置を復帰"
#include "include/IO.js"
#include "include/IO.js"
#icon = "selection_collapse.ico"
// #icon = "selection_collapse.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",212
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",212


165行目: 220行目:


/**
/**
  * sukemaru, 2019/10/21 - 2019/11/13 【include 版】
* ---------------------------------------------------------
* 【include版】 選択範囲を解除 (非スクロール)
  * sukemaru, 2019/10/21 - 2020/11/01
* ---------------------------------------------------------
  * 要:include ライブラリ
  * 要:include ライブラリ
  *  
  *  
  * ・「すべて選択」マクロ実行前の
  * ・「すべて選択」マクロ実行前の
  *    選択範囲(キャレット位置)とスクロール位置の情報を
  *    選択範囲(キャレット位置)とスクロール位置の情報を
  *  JSON ファイルから読みこんで復元する(位置を復帰)。
  *  JSON ファイルから読みこんで復元する(位置を復帰/マルチカーソルに対応)。
  * ・「すべて選択」以外の範囲選択状態から実行したときは
  * ・「すべて選択」以外の範囲選択状態から実行したときは
  *    スクロールなしで範囲選択を解除する。
  *    スクロールなしで範囲選択を解除する。
  * ・「範囲選択なし」の状態から実行したときはキャレット位置までスクロールする。
  * ・「範囲選択なし」の状態から実行したときはキャレット位置までスクロールする。
* ⇒ さらに再実行するとアクティブ行が画面内の先頭になるようにスクロールする。
*
* ・「複数選択範囲」の状態からこのマクロを連続で実行した場合、
*    1回目:各選択範囲のアクティブ側に各カーソルを残す(ゼロ幅のマルチカーソル)。
*    2回目:マルチカーソルを解除する(カーソルを1つだけにする)。
* ※ このマクロは、Mery Ver 3.0.0 以降の Esc キーによる「マルチカーソルの解除」
*  (複数選択範囲からひとつの選択範囲だけを残す)と同等の機能を含めていない。
  *  
  *  
  * ※「すべて選択」の状態から「位置を復帰」したときのみ
  * ※「すべて選択」の状態から「位置を復帰」したときのみ
192行目: 257行目:


var d = editor.ActiveDocument,  s = d.selection;
var d = editor.ActiveDocument,  s = d.selection;
var dText = d.Text,  dLength = dText.length;
var dLength = d.TextLength || d.Text.length;
var act = s.GetActivePos();
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var sx = ScrollX,  sy = ScrollY;
var sx = ScrollX,  sy = ScrollY;
Redraw = false;
var sMode = s.Mode || 0,  sCount = s.Count || 0;
var infoExist = false;
// Redraw = false;


// 「すべて選択」状態のとき
// 「すべて選択」状態のとき
if ( s.Text.length == dLength ) {
if ( ( s.TextLength || s.Text.length ) === dLength ) {
   var dPath = d.FullName || "無題";
   var dPath = d.FullName || "無題";
   var setting = { fileList: [] };
   var setting = { fileList: [] };
   setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
   setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
   var list = setting.fileList;
   var list = setting.fileList;
  var len = list.length;
  var infoExist = false;
  var fileInfo;
  for ( var i = 0; i < len; i ++ ) {


  /**
  * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
  * フルパス (dPath), 文字数 (dLength)
  * 範囲選択モード (mode)
  * 選択範囲の開始/終了位置 (anc, act)
  * マルチカーソル選択範囲 (sel)
  * スクロール位置 (sx, sy), アクティブ行 (ay)
  */
  Loop:
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
     // リストにファイル情報があれば
     // リストにファイル情報があれば
     if ( list[i][0] == dPath ) {
     if ( list[i].path === dPath ) {
      info = list[i];
       infoExist = true;
       infoExist = true;
      fileInfo = list[i];
      /**
      * list[i] = [ dPath, dLength, anc, act, sx, sy ]
      *  フルパス、文字数
      *  選択範囲の開始/終了位置(anc, act)
      *  スクロール位置(sx, sy)
      */
       // 文書の文字数が同じなら、選択範囲とスクロール位置を復元
       // 文書の文字数が同じなら、選択範囲とスクロール位置を復元
       if ( fileInfo[1] == dLength ) {
       if ( info.len === dLength ) {
         Restore( fileInfo[3], fileInfo[4], fileInfo[5], fileInfo[2] );
         // Restore( info.act, info.anc, info.sx, info.sy, info.mode );
        s.SetActivePos( info.act );
        // 複数選択範囲を復帰
        if ( ( sCount = info.sel.length ) > 0 ) {
          for ( var i = 0; i < sCount; i ++ ) {
            s.AddPos( info.sel[i].anc, info.sel[i].act );
          }
          s.AddPos( info.anc, info.act );
        }
        // 通常選択範囲または矩形選択範囲を復帰
        else {
          s.SetAnchorPos( info.anc );
          if ( info.mode == 2 ) { s.Mode = meModeBox; }
        }
        ScrollX = info.sx;  ScrollY = info.sy;
       }
       }
       // 文書の文字数が異なるなら、選択解除 (スクロールしない)
       // 文書の文字数が異なるなら、選択解除 (スクロールしない)
       else {
       else {
         Restore( act, sx, sy );
         Restore( act, act, sx, sy ); // ※ ファイル情報のマルチカーソル選択範囲を無視
       }
       }
       // リストからファイル情報を削除
       // リストからファイル情報を削除
       list.splice( i, 1 );
       list.splice( i, 1 );
       setting.fileList = list;
       setting.fileList = list;
       IO.Serialize( setting, jsonName ); // JSON 書き込み
       IO.Serialize( setting, jsonName ); // JSON 書き込み
       break;
       break Loop;
     }
     }
   }
   } // Loop
}
}


// 「すべて選択」以外の範囲選択状態のときは、選択解除 (スクロールしない)
// 「すべて選択」以外の範囲選択状態のときは、選択解除
if ( ! infoExist && s.Text ) {
if ( ! infoExist && s.Text ) {
   Restore( act, sx, sy );
   // 複数選択範囲なら、ゼロ幅選択のみのマルチカーソル状態にする
  if ( sMode == 3 ) {
    s.Collapse( meCollapseEnd ); // ※ 各選択範囲のアクティブ側にカーソルを残す
  }
  // 複数選択範囲でないなら、選択解除 (スクロールしない)
  else {
    Restore( act, act, sx, sy );
  }
}
}
// 「選択範囲なし」の状態のときは、キャレット位置までスクロールする
// 「選択範囲なし」の状態のときは、キャレット位置までスクロールする
else if ( ! infoExist && s.IsEmpty ) {
// ※ ゼロ幅選択のみのマルチカーソル状態も解除
   s.SelectLine();
else if ( ! infoExist && ! s.Text ) {
   s.SelectLine(); // 選択範囲の変更イベントを発生させる
   s.SetActivePos( act );
   s.SetActivePos( act );
  if ( ScrollY === sy && ! sCount ) {
    ScrollY = s.GetTopPointY( mePosView );
  }
}
}
// Redraw = true;


Redraw = true;


 
// 関数 Restore( activePos, anchorPos, scrollX, scrollY [, selectionMode] )
// 関数 Restore( activePos, scrollX, scrollY [, anchorPos] )
function Restore( act, anc, sx, sy, mode ) {
function Restore( act, sx, sy, anc ) {
  anc = anc >= 0 ? anc : act;
   editor.ActiveDocument.selection.SetActivePos( anc );
   editor.ActiveDocument.selection.SetActivePos( anc );
   editor.ActiveDocument.selection.SetActivePos( act, true );
   editor.ActiveDocument.selection.SetActivePos( act, true );
  if ( mode == 2 ) { s.Mode = mode; }
   ScrollX = sx;  ScrollY = sy;
   ScrollX = sx;  ScrollY = sy;
}
}
</source>
</syntaxhighlight>
 


== 【include 版】位置を復帰/保存 ==
== 【include 版】位置を復帰/保存 ==
単純に '''キャレット位置(選択範囲)を 保存/復元''' するためのマクロです (<b style="color:#0000c0;">マルチカーソルに対応</b>)。


単純にキャレット位置(選択範囲)の情報を 保存/復元 するための 【自家用】 マクロです。<br>
ファイル内の閲覧のさいのスクロールや検索操作をする前などに、任意の位置(キャレット位置/選択範囲/アクティブ行)を '''一時保存''' し、任意のタイミングで復帰することができます。
ファイル内の閲覧のさいのスクロールや検索操作をする前などに、任意の位置(キャレット位置/選択範囲/アクティブ行)を一時保存し、任意のタイミングで復帰することができます。<br>
<span style="color:#c00;">ただし、「位置情報を保存」と「位置を復帰」のあいだに編集操作(文書全体の文字数の変化)があった場合、復帰先は '''保存したアクティブ行番号の行頭位置''' になります。</span><br>
: ※ 「[[#すべて選択|【include版】 すべて選択 (非スクロール)]]」マクロや「[[#選択解除|【include版】 選択範囲を解除 (非スクロール)]]」マクロと連携させて利用する前提で、位置情報保存用の JSON ファイルを共用します。


<div class="warningbox">
※「位置情報を保存」と「位置を復帰」操作のあいだに編集操作(文書全体の文字数の変化)があった場合、復帰先は '''保存したアクティブ行番号の行頭位置''' になります。
* このマクロは、「[[includeライブラリ]]」を利用し、外部ファイル(JSON)に情報を保存/参照します。<br> あらかじめ「includeライブラリ」を '''Mery\Macros''' フォルダに配置してください。
<br>
:* 外部ファイルの保存場所は '''Mery\Macros\MacroSettings\<位置情報を保存>.json''' <br> または '''%AppData%\Mery\MacroSettings\<位置情報を保存>.json''' です。
※ 「[[#すべて選択|【include版】 すべて選択 (非スクロール)]]」マクロや「[[#選択解除|【include版】 選択範囲を解除 (非スクロール)]]」マクロと連携させて利用する前提で、位置情報保存用の JSON ファイルを共用します。
:* 環境によっては、外部ファイルへの書き込みの '''遅延''' などによりエラーが発生することがあるかもしれません。
:* 外部ファイルは「【include版】 すべて選択 (非スクロール)」「【include版】 選択範囲を解除 (非スクロール)」マクロと共用する前提にしてあります。
* このマクロは、「[[GetKeyState.exe(キー状態取得実行ファイル)]]」を使用します。
: あらかじめ ZIP ファイルをダウンロード・解凍して、実行ファイル「GetKeyState.exe」を '''Mery\Macros''' フォルダに配置してください。
</div>


* <span style="color:#0000c0;">Ctrl キーを押しながらこのマクロを実行したときは「'''位置情報を保存'''」します。</span>
* <span style="color:#0000c0;"><kbd>Ctrl</kbd> キーを押しながらこのマクロを実行したときは「'''位置情報を保存'''」します。</span>
: ※ ファイル名、文字数、選択範囲(キャレット位置)とスクロール位置などの情報を JSON ファイルに書き出します。
: ※ ファイル名、文字数、選択範囲(キャレット位置)とスクロール位置などの情報を JSON ファイルに書き出します。


* <span style="color:#0000c0;">Ctrl キーを押さずにこのマクロを実行したときは「'''位置を復帰'''」します。</span>
* <span style="color:#0000c0;"><kbd>Ctrl</kbd> キーを押さずにこのマクロを実行したときは「'''位置を復帰'''」します。</span>
: ※ Ctrl キーを押しながらこのマクロを実行して保存した位置情報か、「[[#すべて選択|【include版】 すべて選択 (非スクロール)]]」マクロ実行前のキャレット位置(選択範囲)を JSON ファイルから読みこんで復元します。
: ※ Ctrl キーを押しながらこのマクロを実行して保存したときの位置情報か、「[[#すべて選択|【include版】 すべて選択 (非スクロール)]]」マクロ実行前のキャレット位置(選択範囲)を JSON ファイルから読みこんで復元します。


* JSON ファイルに保存された情報と文字数がことなるときは、保存された行番号(論理行)の行頭に復帰します。
* <span style="color:#c00;">JSON ファイルに保存された情報と '''文字数がことなる''' ときは、保存された行番号(論理行)の行頭に復帰します。</span>
: ※ 保存された位置情報がマルチカーソルだった場合、シングルカーソルになります。
: ※ 保存されたスクロール位置を復帰せず、キャレット位置までスクロールします。
: ※ 保存されたスクロール位置を復帰せず、キャレット位置までスクロールします。
 
*「位置を復帰」の前後でキャレット位置(選択範囲)に変化がないとき、または JSON ファイルに位置情報がないときは、キャレット位置までスクロールするだけです。
*「位置を復帰」の前後でキャレット位置(選択範囲)に変化がないとき、または JSON ファイルに位置情報がないときは、キャレット位置までスクロールするだけです。


* 「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しません。
* 「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しません。
: ※ Ctrl キーを押しながらこのマクロを実行したとき、または「【include版】 すべて選択 (非スクロール)」マクロ実行時の「位置情報を保存」処理のさいに、開かれていないファイルの位置情報は JSON から削除されます。
: ※ <kbd>Ctrl</kbd> キーを押しながらこのマクロを実行したとき、または「【include版】 すべて選択 (非スクロール)」マクロ実行時の「位置情報を保存」処理のさいに、開かれていないファイルの位置情報は JSON から削除されます。


* <span style="color:#c00;">このマクロには '''アクティブタブの位置情報を削除''' する機能はありません。</spn>
* <span style="color:#c00;">このマクロには '''アクティブタブの位置情報を削除''' する機能はありません。</span>
: このマクロで保存した位置情報を、当該ファイルのタブを閉じずに削除したい場合は、「【include版】 すべて選択 (非スクロール)」マクロと「【include版】 選択範囲を解除 (非スクロール)」マクロをつづけて実行してください。
: このマクロで保存した位置情報を、当該ファイルのタブを閉じずに削除したい場合は、「【include版】 すべて選択 (非スクロール)」マクロと「【include版】 選択範囲を解除 (非スクロール)」マクロをつづけて実行してください。
: ※「すべて選択」の状態から「選択解除」マクロを実行すると(位置の復帰動作)、当該ファイルの位置情報は JSON から削除されます。
: ※「すべて選択」の状態から「選択解除」マクロを実行すると(位置の復帰動作)、当該ファイルの位置情報は JSON から削除されます。
: ※ このマクロ単独で「位置情報を保存/位置を復帰」の運用をする場合、JSON から位置情報を削除するには、当該ファイルのタブを閉じた状態で <u>別のタブ上から「位置情報を保存」の操作</u> をするしかありません (Shift キー押し下げで「削除」という方法もありますが、実行時のタイムラグが大きくなるので保留)。
: ※ このマクロ単独で「位置情報を保存/位置を復帰」の運用をする場合、JSON から位置情報を削除するには、当該ファイルのタブを閉じた状態で <u>別のタブ上から「位置情報を保存」の操作</u> をするしかありません (Shift キー押し下げで「削除」という方法もありますが、実行時のタイムラグが大きくなるので保留)。


<div class="warningbox">
* このマクロは、「[[includeライブラリ]]」を利用し、外部ファイル(JSON)に情報を保存/参照します。<br> あらかじめ「includeライブラリ」を '''Mery\Macros''' フォルダに配置してください。
:* 外部ファイルの保存場所は '''Mery\Macros\MacroSettings\<位置情報を保存>.json''' <br> または '''%AppData%\Mery\MacroSettings\<位置情報を保存>.json''' です。
:* 環境によっては、外部ファイルへの書き込みの '''遅延''' などによりエラーが発生することがあるかもしれません。
:* 外部ファイルは「【include版】 すべて選択 (非スクロール)」「【include版】 選択範囲を解除 (非スクロール)」マクロと共用する前提にしてあります。
* このマクロは、「[[GetKeyState.exe(キー状態取得実行ファイル)]]」を使用します。
: あらかじめ ZIP ファイルをダウンロード・解凍して、実行ファイル「GetKeyState.exe」を '''Mery\Macros''' フォルダに配置してください。
</div>


=== ソースコード ===
=== ソースコード ===
<source lang="javascript" style="height:60em; overflow:auto;">
<syntaxhighlight lang="javascript" style="height:60em; overflow:auto;">
#title = "位置を復帰/保存"
#title = "位置を復帰/保存"
#tooltip = "選択範囲(カーソル位置)を復帰 または 位置情報を保存"
#tooltip = "選択範囲(カーソル位置)を復帰 または 位置情報を保存"
#include "include/IO.js"
#include "include/IO.js"
#icon = "arrows_swap_vertical[1].ico"
// #icon = "arrows_swap_vertical[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",224
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",224


/**
/**
  * sukemaru, 2019/11/13 【include 版】
  * ---------------------------------------------------------
* 【include 版】位置を復帰/保存
*  sukemaru, 2019/11/13 - 2020/11/01
* ---------------------------------------------------------
  * 要:include ライブラリ
  * 要:include ライブラリ
  * 要: GetKeyState.exe
  * 要: GetKeyState.exe
325行目: 414行目:
   // ・ポータブル版: Mery\Macros\MacroSettings\位置情報を保存.json
   // ・ポータブル版: Mery\Macros\MacroSettings\位置情報を保存.json
   // ・インストール版: %AppData%\Mery\MacroSettings\位置情報を保存.json
   // ・インストール版: %AppData%\Mery\MacroSettings\位置情報を保存.json
// ■ GetKeyState.exe のフルパスを指定する場合( \ 記号はふたつがさね「\\」で)
// 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe
var gksPath = ""; // ※ GetKeyState.exe なしのときも "" にする


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


var $ctrl = 0;
var gks = gksPath ||
var getKeyState = editor.FullName.replace( /[^\\]+$/i , "" )
          editor.FullName.replace( /[^\\]+$/i, "Macros\\GetKeyState.exe" );
                + "Macros\\GetKeyState.exe";
var gksCmd = '"' + gks + '" ctrl';
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
var $ctrl = ( new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks )
if ( Fso.FileExists( getKeyState ) ) {
          && new ActiveXObject( "WScript.Shell" ).Run( gksCmd, 0, true ) !== 0 )
  var WshShell = new ActiveXObject( "WScript.Shell" );
          ? true : false;
  $ctrl = WshShell.Run( "\"" + getKeyState + "\" ctrl", 0, true );
}


var d = editor.ActiveDocument,  s = d.selection;
var d = editor.ActiveDocument,  s = d.selection;
var dPath = d.FullName || "無題";
var dPath = d.FullName || "無題";
var dText = d.Text,  dLength = dText.length;
var dLength = d.TextLength || d.Text.length;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var anc = s.GetAnchorPos(),  act = s.GetActivePos();
var sx = ScrollX,  sy = ScrollY;
var sx = ScrollX,  sy = ScrollY;
var sMode = s.Mode || 0;


var setting = { fileList: [] };
var setting = { fileList: [] };
setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
setting = IO.Deserialize( setting, jsonName ); // JSON 読み込み
var list = setting.fileList;
var infoExist = false;
var infoExist = false;
 
var v3 = ( "AddUndo" in window );
var list = setting.fileList;
var len = list.length;


// 位置を復帰
// 位置を復帰
if ( $ctrl == 0 ) {
if ( ! $ctrl ) {
   Redraw = false;
   // Redraw = false;
 
   var meFindKeepOptions;
   for ( var i = 0, fileInfo; i < len; i ++ ) {
  /**
    fileInfo = list[i];
  * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
      /**
  * フルパス (dPath), 文字数 (dLength)
      * list[i] = [ dPath, dLength, anc, act, sx, sy, ay ]
  * 範囲選択モード (mode)
      * フルパス、文字数
  * 選択範囲の開始/終了位置 (anc, act)
      * 選択範囲の開始/終了位置(anc, act)
  * マルチカーソル選択範囲 (sel)
      * スクロール位置(sx, sy)
  * スクロール位置 (sx, sy), アクティブ行 (ay)
      */
  */
 
  ListLoop1:
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
    info = list[i];
     // リストにファイル情報があれば
     // リストにファイル情報があれば
     if ( fileInfo[0] == dPath ) {
     if ( info.path === dPath ) {
       infoExist = true;
       infoExist = true;
       // 文書の文字数が同じなら、選択範囲(キャレット位置)を復元
       // 文書の文字数が同じなら、選択範囲(キャレット位置)を復元
       if ( fileInfo[1] == dLength ) {
       if ( info.len === dLength ) {
         s.SetAnchorPos( fileInfo[2] );
         s.SetActivePos( info.act );
         s.SetActivePos( fileInfo[3], true );
         /* マルチカーソル選択範囲を復帰 */
         ScrollX = fileInfo[4];
        if ( ( sCount = info.sel.length ) > 0 ) {
         ScrollY = fileInfo[5];
          for ( var i = 0; i < sCount; i ++ ) {
            s.AddPos( info.sel[i].anc, info.sel[i].act );
          }
          s.AddPos( info.anc, info.act );
         }
        // 通常選択範囲または矩形選択範囲を復帰
        else {
          s.SetAnchorPos( info.anc );
          if ( info.mode == 2 ) { s.Mode = meModeBox; }
         }
        ScrollX = info.sx;  ScrollY = info.sy;
       }
       }
      // 文書の文字数が異なるなら、行番号(行頭)に復帰
       else {
       else {
        // 文書の文字数が異なるなら、行番号(行頭)に復帰
         s.SetActivePoint( mePosLogical, 1, info.ay, false );
         s.SetActivePoint( mePosLogical, 1, fileInfo[6], false );
       }
       }
       // 実行前と選択範囲が同じならスクロールする
       // 実行前と選択範囲が同じならスクロールする
       if ( s.GetActivePos() == act && s.GetAnchorPos() == anc ) {
       if ( s.GetActivePos() === act && s.GetAnchorPos() === anc ) {
         var yy = s.GetActivePointY( mePosView );
         ScrollY = s.GetTopPointY( mePosView );
         ScrollY = yy;
         ScrollX = ( ScrollX === 1 ) ? 1
        // var xx = s.GetActivePointX( mePosView );
                : s.GetTopPointX( mePosView );
        // ScrollX = xx;
       }
       }
       break;
       break ListLoop1;
     }
     }
   }
   } // ListLoop1


   // ファイル情報がないときは、キャレット位置までスクロールするだけ
   // ファイル情報がないときは、キャレット位置までスクロールするだけ
   if ( ! infoExist  ) {
   if ( ! infoExist  ) {
     s.SetActivePos( anc );
     if ( sMode == 3 ) {
    s.SetActivePos( act, true );
      s.AddPos( anc, act );
    }
    else {
      s.SetActivePos( anc );
      s.SetActivePos( act, true );
      s.Mode = sMode;
    }
    if ( ScrollY === sy ) {
      ScrollY = s.GetTopPointY( mePosView );
    }
   }
   }
 
   // Redraw = true;
   Redraw = true;
}
}


// 位置情報を保存
// 位置情報を保存
else if ( $ctrl == 1 ) {
else { // if ( $ctrl )
  var ay = s.GetActivePointY( mePosLogical );
  var eCount = Editors.Count,  docus,  dCount,  hit;
  /* マルチカーソル対応 */
  var sCount = s.Count || 0,  Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = { act: s.GetActivePos( i ),  anc: s.GetAnchorPos( i ) };
  }
   /**
   /**
   * フルパス、文字数
   * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
   * 選択範囲の開始/終了位置(anc, act)
   * フルパス (dPath), 文字数 (dLength)
   * スクロール位置(sx, sy)、アクティブ行(ay)
   * 範囲選択モード (mode)
  * 選択範囲の開始/終了位置 (anc, act)
  * マルチカーソル選択範囲 (sel)
  * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
   */
   var ay = s.GetActivePointY( mePosLogical );
   ListLoop2: // ※ list.length はループ中に変動する
   for ( var i = 0, path; i < list.length; i ++ ) {
   for ( var i = 0, path; i < list.length; i ++ ) {
     path = list[i][0];
     path = list[i].path;
 
     // リストにファイルの情報があれば書き換える
     // リストにファイルの情報があれば書き換える
     if ( path == dPath ) {
     if ( path === dPath ) {
       infoExist = true;
       infoExist = true;
       list[i] = [ dPath, dLength, anc, act, sx, sy, ay ];
       list[i] = {
        path: dPath, len: dLength, mode: sMode,
        anc: anc, act: act, sel: Sel,
        sx: sx, sy: sy, ay: ay
      };
     }
     }
     // リストに現在開かれていないファイルの情報があれば削除する
     // リストに現在開かれていないファイルの情報があれば削除する
     else {
     else {
       var eCount = Editors.Count;
       DeleteLoop:
      var docus,  dCount,  filePath,  hit;
       for ( var ee = 0, hit = false; ee < eCount; ee ++ ) {
       for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
         docus = Editors.Item( ee ).Documents;
         docus = Editors.Item( ee ).Documents;
         dCount = docus.Count;
         dCount = docus.Count;
         for ( var dd = 0; dd < dCount; dd ++ ) {
         for ( var dd = 0; dd < dCount; dd ++ ) {
           filePath = docus.Item( dd ).FullName;
           if ( docus.Item( dd ).FullName === path ) { hit = true }
          if ( path == filePath ) { hit ++ }
         }
         }
       }
       } // DeleteLoop
      // リストから削除して、ループ処理の i をひとつ巻き戻す
       if ( ! hit ) { list.splice( i --, 1 ) }
       if ( ! hit ) { list.splice( i --, 1 ) }
     }
     }
   }
   } // ListLoop2:


   // リストにファイルの情報がなければ追加する
   // リストにファイルの情報がなければ追加する
   if ( ! infoExist ) {
   if ( ! infoExist ) {
     list.push( [ dPath, dLength, anc, act, sx, sy, ay ] );
     list.push( {
      path: dPath, len: dLength, mode: sMode,
      anc: anc, act: act, sel: Sel,
      sx: sx, sy: sy, ay: ay
    } );
   }
   }


   setting.fileList = list;
   setting.fileList = list;
   IO.Serialize( setting, jsonName ); // JSON 書き込み
   IO.Serialize( setting, jsonName ); // JSON 書き込み
  var str = " " + ( act === anc ? "位置" : "選択範囲" ) + "を保存";
  if ( Status.indexOf( "文字" ) > -1 && Status.indexOf( "行" ) > -1
  && ! /(?:位置|選択範囲)を保存/.test( Status ) ) {
    Status += str;
  }
  else if ( Status.indexOf( "文字" ) < 0 && Status.indexOf( "行" ) < 0 ) {
    Status = str;
  }
}
}


458行目: 592行目:
  *  または JSON ファイルに位置情報がないときは、
  *  または JSON ファイルに位置情報がないときは、
  *  キャレット位置にスクロールするだけ。
  *  キャレット位置にスクロールするだけ。
* ⇒ さらに再実行すると選択範囲の先頭行が画面内の先頭になるようにスクロールする。
  *  
  *  
  * ・「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しない。
  * ・「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しない。
472行目: 607行目:
  *    別のタブ上から「位置情報を保存」操作をするしかない。
  *    別のタブ上から「位置情報を保存」操作をするしかない。
  */
  */
</source>
</syntaxhighlight>
 
== メモ ==
* (2020/11/01, sukemaru)
:・画面の強制再描画によるチラツキを防ぐために、各ソースコード内の <syntaxhighlight lang="javascript" inline>Redraw = false</syntaxhighlight> <syntaxhighlight lang="javascript" inline>Redraw = true</syntaxhighlight> の処理をコメントアウトしました。
:・Mery Ver 3.0.0 以降では <code>Document.Tag</code> プロパティを利用すれば複数の「'''無題-<n>'''」タブの位置情報を <q>個別</q> に保存/復帰できるのですが、その場合、タブの開きなおしや Mery の再起動で位置情報が消えてしまいます。<br> ⇒ ワークスペース機能を利用している場合の利便性を優先するために、外部ファイル(JSON)を利用する仕様のままにしました。
:・このマクロでは、Mery Ver 3.1.0 以降で [ウインドウの分割(上下/左右)] 機能を利用しているさいに、分割ペインごとの位置情報(選択範囲・スクロール状態)を <q>個別</q> に保存/復帰することはできません。<br>※ アクティブなエディターペイン上で動作するはずですが、Mery アルファ/ベータ版のバージョンごとの動作検証はしていません。

2024年9月9日 (月) 10:02時点における最新版

「すべて選択 (Ctrl+A)」を実行して全文コピーやステータスバーで文書全体の文字数・行数などを確認したときにキャレットやスクロール位置がスッ飛んでいってしまったり、選択範囲を解除 したときにも同様のことが起こったりするので、状況によってはスクロール位置とキャレット位置を元に戻す手間が面倒ですよね…。

ダウンロード[編集]

>> 「ファイル:【include 版】すべて選択/選択解除.zip (アイコン入り)」
  • 2019/10/21: 【include 版】の初版
  • 2019/10/27: 【include 版】の第2版(描画速度を微妙に改善)
  • 2019/11/13: 【include 版】の第3版
  • 「位置を復帰/保存」マクロを追加
  • マクロ追加により既存マクロのコードを微修正
  • JSON ファイル名の既定値を変更 「すべて選択」 → 「位置情報を保存」
  • 2020/11/01: 【include 版】の第4版
  • リストに保存する各ファイルの情報を オブジェクト.プロパティ 形式に変更 (※ 以前のバージョンでの JSON ファイルと互換性なし)
  • Mery Ver 3.0.1 以降のマルチカーソル選択範囲の保存/復帰可 (※ ウインドウの「分割」状態には非対応)

【include 版】すべて選択/選択解除 (非スクロール)[編集]

以下のふたつのマクロを使って「すべて選択」/「選択範囲を解除」すると、無用なスクロールやキャレット移動がなくなります。
また、ふたつのマクロを交互に実行することで「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えができます (マルチカーソルに対応)。

お好みでツールバー(マクロバー)アイコンに登録するか、キーボードショートカットに割りあててご利用下さい。
※ すでに キーアサイン集 の「すべて選択 (非スクロール)」「選択範囲を解除 (非スクロール)」マクロを導入している場合は、当マクロのソースコードで上書き保存するのがよいとおもいます。

【include版】 すべて選択 (非スクロール)
  • 「すべて選択」を実行する前のキャレット位置とスクロール位置を保存してから「すべて選択 (非スクロール)」を実行します「すべて選択」前に選択範囲があった場合は、選択範囲の開始/終了位置を保存します。
  • 開いているタブごとに位置情報を保存し、すでに閉じられたタブの情報は逐次削除します。
  • 「無題-<n>」タブの情報は ファイル名 = "無題" として保存します。
    ※ 複数の「無題」のタブの位置情報を個別に保存することはできません。
    ※ 「選択解除」するまえに別の「無題-<m>」タブでこのマクロを実行すると "無題" の位置情報は上書きされます。
  • 「すべて選択」状態からこのマクロを再実行した場合は、保存された位置情報・選択範囲を復帰します。(2020/11/01)
    ※ この場合、保存されている位置情報・選択範囲を削除しません。
【include版】 選択範囲を解除 (非スクロール)
  • 「すべて選択」の状態で実行したときのみ、「【include版】 すべて選択 (非スクロール)」マクロが保存した情報を利用して、キャレット位置とスクロール位置を復元します。
    ※ 保存されている当該タブの位置情報は、このマクロの実行時に削除されます。
    ※「すべて選択」状態を解除したときに復元された選択範囲は、このマクロをもう一度実行すると完全に解除されます。
  • 「【include版】 すべて選択 (非スクロール)」マクロが保存した位置情報がない場合は「選択範囲を解除 (非スクロール)」を実行します。
  • ホイールスクロールなどによりキャレットが表示領域内にない状態、かつ「選択範囲なし」の状態で実行したときは、キャレットのある行まで画面をスクロールします。
  • 「マルチカーソル・複数選択範囲」の状態からこのマクロを連続で実行した場合 … (2020/11/01)
    1回目:各選択範囲のアクティブ側に各カーソルを残す(ゼロ幅のマルチカーソル)。
    2回目:マルチカーソルを解除する(カーソルを1つだけにする)。
    ※ このマクロには、Mery Ver 3.0.0 以降の Esc キーによる「マルチカーソルの解除」と同等の機能(複数選択範囲からひとつの選択範囲だけを残す)を 含めていません。
  • このページのマクロは、「includeライブラリ」を利用し、外部ファイル(JSON)に情報を保存/参照します。
    あらかじめ「includeライブラリ」を Macros フォルダに配置してください。
  • 外部ファイルの保存場所は Mery\Macros\MacroSettings\<位置情報を保存>.json
    または %AppData%\Mery\MacroSettings\<位置情報を保存>.json です。
  • 環境によっては、外部ファイルへの書き込みの 遅延 などによりエラーが発生することがあるかもしれません。
  • JSON ファイルには、アクティブなタブの 「ファイルパス」 「全文字数」 「範囲選択モード」 「選択範囲の開始/終了位置」 「マルチカーソル選択範囲」 「スクロール位置」 「アクティブ行番号」 を保存します。
    複数のタブで「すべて選択」を実行した場合は、それぞれのタブの情報が保存されます。
  • JSON ファイルへのファイルアクセスが最小限になる仕様にしてあります。
    また、「すべて選択」で位置情報を保存するときに、JSON ファイルに「他のタブで開かれていないファイルの位置情報」があれば、それらのファイル情報は逐次削除するので、JSON ファイルが肥大化することはありません。

※ 選択範囲(キャレット位置)を保存/復帰するためのマクロ を追加しました。

  • 「任意の範囲選択状態」と「すべて選択状態」のトグル切り替えのさいに保存した位置情報を破棄せず、繰り返して「位置を復帰」の操作ができるようになります。

ソースコード[編集]

【include版】 すべて選択 (非スクロール)[編集]

#title = "すべて選択 (位置を保存・非スクロール)"
#tooltip = "位置情報を保存してから すべて選択 (スクロールしない)"
#include "include/IO.js"
// #icon = "select_all.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",111

// 推奨割当:「Ctrl + A」

/**
 * ---------------------------------------------------------
 * 【include版】 すべて選択 (非スクロール)
 *  sukemaru, 2019/10/21 - 2020/11/01
 * ---------------------------------------------------------
 * 要:include ライブラリ
 * 
 * ・「すべて選択」前の選択範囲(キャレット位置)とスクロール位置などの
 *   情報を JSON ファイルに書き出す。
 *   → 「選択解除」「位置を復帰」マクロで、保存した位置情報に復元可。
 * ・「すべて選択」状態から再実行すると「位置を復帰」(2020/11/01)
 * 
 * ※ すべて選択状態から「選択解除」マクロで「位置を復帰」すると、
 *    当該ファイルの位置情報は JSON から削除される。
 * 
 * ・JSON にはファイルパスごとに位置情報を保存する。
 * ・JSON のリストに現在開かれていないファイルの情報があれば削除する。
 */

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

// 位置情報の保存用ファイルのベース名
var jsonName = "位置情報を保存";

  // ※ 「すべて選択」 「選択解除」 「位置を復帰」 マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "位置情報を保存" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\位置情報を保存.json
  // ・インストール版: %AppData%\Mery\MacroSettings\位置情報を保存.json
  
// ---------- ▲ 設定項目 ▲ ----------

var d = editor.ActiveDocument,  s = d.selection;
var dPath = d.FullName || "無題";
var dLength = d.TextLength || d.Text.length;
var setting = { fileList: [] };
var list,  len;
var sMode = s.Mode || 0;

if ( ( s.TextLength || s.Text.length ) !== dLength ) {
  if ( sMode > 1 && ! d.ReadOnly ) { AddUndo(); }

  /**
   * フルパス (dPath), 文字数 (dLength)
   * 範囲選択モード (mode)
   * 選択範囲の開始/終了位置 (anc, act)
   * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
  var anc = s.GetAnchorPos(),  act = s.GetActivePos();
  var sx = ScrollX,  sy = ScrollY;
  var ay = s.GetActivePointY( mePosLogical );
  /* マルチカーソル対応 */
  var sCount = s.Count || 0,  Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = { act: s.GetActivePos( i ),  anc: s.GetAnchorPos( i ) };
  }

  // すべて選択 (スクロールしない)
  // Redraw = false;
  s.SelectAll();
  ScrollX = sx;  ScrollY = sy;
  // Redraw = true;
  var eCount = Editors.Count,  docus,  dCount,  hit;
  setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み
  list = setting.fileList;
  var infoExist = false;

  ListLoop:	// ※ list.length はループ中に変動する
  for ( var i = 0, path; i < list.length; i ++ ) {
    path = list[i].path;
    // リストにファイルの情報があれば書き換える
    if ( path === dPath ) {
      infoExist = true;
      list[i] = {
        path: dPath,  len: dLength,  mode: sMode,
        anc: anc,  act: act,  sel: Sel,
        sx: sx,  sy: sy,  ay: ay
      };
    }
    // リストに現在開かれていないファイルの情報があれば削除する
    else {
      DeleteLoop:
      for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
        docus = Editors.Item( ee ).Documents;
        dCount = docus.Count;
        for ( var dd = 0; dd < dCount; dd ++ ) {
          if ( docus.Item( dd ).FullName === path ) { hit ++ }
        }
      }	// DeleteLoop
      // リストから削除し、ループ処理の i をひとつ巻き戻す
      if ( ! hit ) { list.splice( i --, 1 ) }
    }
  }	// ListLoop

  // リストにファイルの情報がなければ追加する
  if ( ! infoExist ) {
    list.push( {
      path : dPath,  len: dLength,  mode: sMode,
      anc: anc,  act: act,  sel: Sel,
      sx: sx,  sy: sy,  ay: ay
    } );
  }

  setting.fileList = list;
  IO.Serialize( setting, jsonName );	// JSON 書き込み
}

/* 「すべて選択」 の状態から位置を復帰する(位置情報を削除しない) */
else if ( dLength ) {
  setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み
  list = setting.fileList;
  /**
   * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
   * フルパス (dPath), 文字数 (dLength)
   * 範囲選択モード (mode)
   * 選択範囲の開始/終了位置 (anc, act)
   * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
    info = list[i];
    // リストにファイル情報があれば
    // 文書の文字数が同じなら、選択範囲(キャレット位置)を復元
    if ( info.path === dPath && info.len === dLength ) {
      // Redraw = false;
      s.SetActivePos( info.act );
      /* マルチカーソル選択範囲を復帰 */
      if ( ( sCount = info.sel.length ) > 0 ) {
        for ( var i = 0; i < sCount; i ++ ) {
          s.AddPos( info.sel[i].anc, info.sel[i].act );
        }
        s.AddPos( info.anc, info.act );
      }
      // 通常選択範囲または矩形選択範囲を復帰
      else {
        s.SetAnchorPos( info.anc );
        if ( info.mode === 2 ) { s.Mode = meModeBox; }
      }
      ScrollX = info.sx;  ScrollY = info.sy;
      // Redraw = true;
      break;
    }
  }
}


/*
 * JSON ファイルの初期値
 * {"fileList":[]}
 */

【include版】 選択範囲を解除 (非スクロール)[編集]

#title = "選択解除 (位置を復帰・非スクロール)"
#tooltip = "範囲選択を解除 (スクロールしない) または 位置を復帰"
#include "include/IO.js"
// #icon = "selection_collapse.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",212

// 推奨割当:「Esc」

/**
 * ---------------------------------------------------------
 * 【include版】 選択範囲を解除 (非スクロール)
 * sukemaru, 2019/10/21 - 2020/11/01
 * ---------------------------------------------------------
 * 要:include ライブラリ
 * 
 * ・「すべて選択」マクロ実行前の
 *    選択範囲(キャレット位置)とスクロール位置の情報を
 *   JSON ファイルから読みこんで復元する(位置を復帰/マルチカーソルに対応)。
 * ・「すべて選択」以外の範囲選択状態から実行したときは
 *    スクロールなしで範囲選択を解除する。
 * ・「範囲選択なし」の状態から実行したときはキャレット位置までスクロールする。
 * ⇒ さらに再実行するとアクティブ行が画面内の先頭になるようにスクロールする。
 * 
 * ・「複数選択範囲」の状態からこのマクロを連続で実行した場合、
 *    1回目:各選択範囲のアクティブ側に各カーソルを残す(ゼロ幅のマルチカーソル)。
 *    2回目:マルチカーソルを解除する(カーソルを1つだけにする)。
 * ※ このマクロは、Mery Ver 3.0.0 以降の Esc キーによる「マルチカーソルの解除」
 *  (複数選択範囲からひとつの選択範囲だけを残す)と同等の機能を含めていない。
 * 
 * ※「すべて選択」の状態から「位置を復帰」したときのみ
 *    当該ファイルの位置情報を JSON から削除する。
 */

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

// 位置情報の保存用ファイルのベース名
var jsonName = "位置情報を保存";

  // ※ 「すべて選択」 「選択解除」 「位置を復帰」 マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "位置情報を保存" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\位置情報を保存.json
  // ・インストール版: %AppData%\Mery\MacroSettings\位置情報を保存.json
  
// ---------- ▲ 設定項目 ▲ ----------

var d = editor.ActiveDocument,  s = d.selection;
var dLength = d.TextLength || d.Text.length;
var act = s.GetActivePos(),  anc = s.GetAnchorPos();
var sx = ScrollX,  sy = ScrollY;
var sMode = s.Mode || 0,  sCount = s.Count || 0;
var infoExist = false;
// Redraw = false;

// 「すべて選択」状態のとき
if ( ( s.TextLength || s.Text.length ) === dLength ) {
  var dPath = d.FullName || "無題";
  var setting = { fileList: [] };
  setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み
  var list = setting.fileList;

  /**
   * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
   * フルパス (dPath), 文字数 (dLength)
   * 範囲選択モード (mode)
   * 選択範囲の開始/終了位置 (anc, act)
   * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
  Loop:
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
    // リストにファイル情報があれば
    if ( list[i].path === dPath ) {
      info = list[i];
      infoExist = true;
      // 文書の文字数が同じなら、選択範囲とスクロール位置を復元
      if ( info.len === dLength ) {
        // Restore( info.act, info.anc, info.sx, info.sy, info.mode );
        s.SetActivePos( info.act );
        // 複数選択範囲を復帰
        if ( ( sCount = info.sel.length ) > 0 ) {
          for ( var i = 0; i < sCount; i ++ ) {
            s.AddPos( info.sel[i].anc, info.sel[i].act );
          }
          s.AddPos( info.anc, info.act );
        }
        // 通常選択範囲または矩形選択範囲を復帰
        else {
          s.SetAnchorPos( info.anc );
          if ( info.mode == 2 ) { s.Mode = meModeBox; }
        }
        ScrollX = info.sx;  ScrollY = info.sy;
      }
      // 文書の文字数が異なるなら、選択解除 (スクロールしない)
      else {
        Restore( act, act, sx, sy );	// ※ ファイル情報のマルチカーソル選択範囲を無視
      }
      // リストからファイル情報を削除
      list.splice( i, 1 );
      setting.fileList = list;
      IO.Serialize( setting, jsonName );	// JSON 書き込み
      break Loop;
    }
  }	// Loop
}

// 「すべて選択」以外の範囲選択状態のときは、選択解除
if ( ! infoExist && s.Text ) {
  // 複数選択範囲なら、ゼロ幅選択のみのマルチカーソル状態にする
  if ( sMode == 3 ) {
    s.Collapse( meCollapseEnd );	// ※ 各選択範囲のアクティブ側にカーソルを残す
  }
  // 複数選択範囲でないなら、選択解除 (スクロールしない)
  else {
    Restore( act, act, sx, sy );
  }
}
// 「選択範囲なし」の状態のときは、キャレット位置までスクロールする
// ※ ゼロ幅選択のみのマルチカーソル状態も解除
else if ( ! infoExist && ! s.Text ) {
  s.SelectLine();	// 選択範囲の変更イベントを発生させる
  s.SetActivePos( act );
  if ( ScrollY === sy && ! sCount ) { 
    ScrollY = s.GetTopPointY( mePosView );
  }
}
// Redraw = true;


// 関数 Restore( activePos, anchorPos, scrollX, scrollY [, selectionMode] )
function Restore( act, anc, sx, sy, mode ) {
  editor.ActiveDocument.selection.SetActivePos( anc );
  editor.ActiveDocument.selection.SetActivePos( act, true );
  if ( mode == 2 ) { s.Mode = mode; }
  ScrollX = sx;  ScrollY = sy;
}

【include 版】位置を復帰/保存[編集]

単純に キャレット位置(選択範囲)を 保存/復元 するためのマクロです (マルチカーソルに対応)。

ファイル内の閲覧のさいのスクロールや検索操作をする前などに、任意の位置(キャレット位置/選択範囲/アクティブ行)を 一時保存 し、任意のタイミングで復帰することができます。

※「位置情報を保存」と「位置を復帰」操作のあいだに編集操作(文書全体の文字数の変化)があった場合、復帰先は 保存したアクティブ行番号の行頭位置 になります。
※ 「【include版】 すべて選択 (非スクロール)」マクロや「【include版】 選択範囲を解除 (非スクロール)」マクロと連携させて利用する前提で、位置情報保存用の JSON ファイルを共用します。

  • Ctrl キーを押しながらこのマクロを実行したときは「位置情報を保存」します。
※ ファイル名、文字数、選択範囲(キャレット位置)とスクロール位置などの情報を JSON ファイルに書き出します。
  • Ctrl キーを押さずにこのマクロを実行したときは「位置を復帰」します。
※ Ctrl キーを押しながらこのマクロを実行して保存したときの位置情報か、「【include版】 すべて選択 (非スクロール)」マクロ実行前のキャレット位置(選択範囲)を JSON ファイルから読みこんで復元します。
  • JSON ファイルに保存された情報と 文字数がことなる ときは、保存された行番号(論理行)の行頭に復帰します。
※ 保存された位置情報がマルチカーソルだった場合、シングルカーソルになります。
※ 保存されたスクロール位置を復帰せず、キャレット位置までスクロールします。
  • 「位置を復帰」の前後でキャレット位置(選択範囲)に変化がないとき、または JSON ファイルに位置情報がないときは、キャレット位置までスクロールするだけです。
  • 「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しません。
※ Ctrl キーを押しながらこのマクロを実行したとき、または「【include版】 すべて選択 (非スクロール)」マクロ実行時の「位置情報を保存」処理のさいに、開かれていないファイルの位置情報は JSON から削除されます。
  • このマクロには アクティブタブの位置情報を削除 する機能はありません。
このマクロで保存した位置情報を、当該ファイルのタブを閉じずに削除したい場合は、「【include版】 すべて選択 (非スクロール)」マクロと「【include版】 選択範囲を解除 (非スクロール)」マクロをつづけて実行してください。
※「すべて選択」の状態から「選択解除」マクロを実行すると(位置の復帰動作)、当該ファイルの位置情報は JSON から削除されます。
※ このマクロ単独で「位置情報を保存/位置を復帰」の運用をする場合、JSON から位置情報を削除するには、当該ファイルのタブを閉じた状態で 別のタブ上から「位置情報を保存」の操作 をするしかありません (Shift キー押し下げで「削除」という方法もありますが、実行時のタイムラグが大きくなるので保留)。
  • このマクロは、「includeライブラリ」を利用し、外部ファイル(JSON)に情報を保存/参照します。
    あらかじめ「includeライブラリ」を Mery\Macros フォルダに配置してください。
  • 外部ファイルの保存場所は Mery\Macros\MacroSettings\<位置情報を保存>.json
    または %AppData%\Mery\MacroSettings\<位置情報を保存>.json です。
  • 環境によっては、外部ファイルへの書き込みの 遅延 などによりエラーが発生することがあるかもしれません。
  • 外部ファイルは「【include版】 すべて選択 (非スクロール)」「【include版】 選択範囲を解除 (非スクロール)」マクロと共用する前提にしてあります。
あらかじめ ZIP ファイルをダウンロード・解凍して、実行ファイル「GetKeyState.exe」を Mery\Macros フォルダに配置してください。

ソースコード[編集]

#title = "位置を復帰/保存"
#tooltip = "選択範囲(カーソル位置)を復帰 または 位置情報を保存"
#include "include/IO.js"
// #icon = "arrows_swap_vertical[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",224

/**
 * ---------------------------------------------------------
 * 【include 版】位置を復帰/保存
 *  sukemaru, 2019/11/13 - 2020/11/01
 * ---------------------------------------------------------
 * 要:include ライブラリ
 * 要: GetKeyState.exe
 * 
 * ※ 能書きはソースコード末尾のコメントブロックに。
 */

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

// ■ 位置情報の保存用ファイルのベース名
var jsonName = "位置情報を保存";

  // ※ 「すべて選択」 「選択解除」 「位置を復帰」 マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "位置情報を保存" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\位置情報を保存.json
  // ・インストール版: %AppData%\Mery\MacroSettings\位置情報を保存.json


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

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

var gks = gksPath ||
          editor.FullName.replace( /[^\\]+$/i, "Macros\\GetKeyState.exe" );
var gksCmd = '"' + gks + '" ctrl';
var $ctrl = ( new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks )
          && new ActiveXObject( "WScript.Shell" ).Run( gksCmd, 0, true ) !== 0 )
          ? true : false;

var d = editor.ActiveDocument,  s = d.selection;
var dPath = d.FullName || "無題";
var dLength = d.TextLength || d.Text.length;
var anc = s.GetAnchorPos(),  act = s.GetActivePos();
var sx = ScrollX,  sy = ScrollY;
var sMode = s.Mode || 0;

var setting = { fileList: [] };
setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み
var list = setting.fileList;
var infoExist = false;
var v3 = ( "AddUndo" in window );

// 位置を復帰
if ( ! $ctrl ) {
  // Redraw = false;
  var meFindKeepOptions;
  /**
   * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
   * フルパス (dPath), 文字数 (dLength)
   * 範囲選択モード (mode)
   * 選択範囲の開始/終了位置 (anc, act)
   * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
  ListLoop1:
  for ( var i = 0, len = list.length, info; i < len; i ++ ) {
    info = list[i];
    // リストにファイル情報があれば
    if ( info.path === dPath ) {
      infoExist = true;
      // 文書の文字数が同じなら、選択範囲(キャレット位置)を復元
      if ( info.len === dLength ) {
        s.SetActivePos( info.act );
        /* マルチカーソル選択範囲を復帰 */
        if ( ( sCount = info.sel.length ) > 0 ) {
          for ( var i = 0; i < sCount; i ++ ) {
            s.AddPos( info.sel[i].anc, info.sel[i].act );
          }
          s.AddPos( info.anc, info.act );
        }
        // 通常選択範囲または矩形選択範囲を復帰
        else {
          s.SetAnchorPos( info.anc );
          if ( info.mode == 2 ) { s.Mode = meModeBox; }
        }
        ScrollX = info.sx;  ScrollY = info.sy;
      }
      // 文書の文字数が異なるなら、行番号(行頭)に復帰
      else {
        s.SetActivePoint( mePosLogical, 1, info.ay, false );
      }
      // 実行前と選択範囲が同じならスクロールする
      if ( s.GetActivePos() === act && s.GetAnchorPos() === anc ) {
        ScrollY = s.GetTopPointY( mePosView );
        ScrollX = ( ScrollX === 1 ) ? 1
                : s.GetTopPointX( mePosView );
      }
      break ListLoop1;
    }
  }	// ListLoop1

  // ファイル情報がないときは、キャレット位置までスクロールするだけ
  if ( ! infoExist  ) {
    if ( sMode == 3 ) {
      s.AddPos( anc, act );
    }
    else {
      s.SetActivePos( anc );
      s.SetActivePos( act, true );
      s.Mode = sMode;
    }
    if ( ScrollY === sy ) {
      ScrollY = s.GetTopPointY( mePosView );
    }
  }
  // Redraw = true;
}

// 位置情報を保存
else {	// if ( $ctrl )
  var ay = s.GetActivePointY( mePosLogical );
  var eCount = Editors.Count,  docus,  dCount,  hit;
  /* マルチカーソル対応 */
  var sCount = s.Count || 0,  Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = { act: s.GetActivePos( i ),  anc: s.GetAnchorPos( i ) };
  }
  /**
   * list[i] = { path, len, mode, anc, act, sel, sx, sy, ay }
   * フルパス (dPath), 文字数 (dLength)
   * 範囲選択モード (mode)
   * 選択範囲の開始/終了位置 (anc, act)
   * マルチカーソル選択範囲 (sel)
   * スクロール位置 (sx, sy), アクティブ行 (ay)
   */
  ListLoop2:	// ※ list.length はループ中に変動する
  for ( var i = 0, path; i < list.length; i ++ ) {
    path = list[i].path;
    // リストにファイルの情報があれば書き換える
    if ( path === dPath ) {
      infoExist = true;
      list[i] = {
        path: dPath,  len: dLength,  mode: sMode,
        anc: anc,  act: act,  sel: Sel,
        sx: sx,  sy: sy,  ay: ay
      };
    }
    // リストに現在開かれていないファイルの情報があれば削除する
    else {
      DeleteLoop:
      for ( var ee = 0, hit = false; ee < eCount; ee ++ ) {
        docus = Editors.Item( ee ).Documents;
        dCount = docus.Count;
        for ( var dd = 0; dd < dCount; dd ++ ) {
          if ( docus.Item( dd ).FullName === path ) { hit = true }
        }
      }	// DeleteLoop
      // リストから削除して、ループ処理の i をひとつ巻き戻す
      if ( ! hit ) { list.splice( i --, 1 ) }
    }
  }	// ListLoop2:

  // リストにファイルの情報がなければ追加する
  if ( ! infoExist ) {
    list.push( {
      path: dPath,  len: dLength,  mode: sMode,
      anc: anc,  act: act,  sel: Sel,
      sx: sx,  sy: sy,  ay: ay
    } );
  }


  setting.fileList = list;
  IO.Serialize( setting, jsonName );	// JSON 書き込み
  var str = " " + ( act === anc ? "位置" : "選択範囲" ) + "を保存";
  if ( Status.indexOf( "文字" ) > -1 && Status.indexOf( "行" ) > -1
  && ! /(?:位置|選択範囲)を保存/.test( Status ) ) {
    Status += str;
  }
  else if ( Status.indexOf( "文字" ) < 0 && Status.indexOf( "行" ) < 0 ) {
    Status = str;
  }
}


/**
 * ・Ctrl キーを押しながらこのマクロを実行したときは「位置情報を保存」する。
 *  ※ ファイル名、文字数、選択範囲(キャレット位置)とスクロール位置などの
 *    情報を JSON ファイルに書き出す。
 * 
 * ・Ctrl キーを押さずにこのマクロを実行したときは「位置を復帰」する。
 *  ※ Ctrl キーを押しながらこのマクロを実行して保存した位置情報か、
 *   「すべて選択」マクロ実行前のキャレット位置(選択範囲)を
 *    JSON ファイルから読みこんで復元する。
 * 
 * ・JSON ファイルに保存された情報と文字数がことなるときは、
 *   保存された行番号(論理行)の行頭に復帰する。
 *  ※ 保存されたスクロール位置を復帰せず、キャレット位置までスクロールする。
 * 
 * ・「位置を復帰」の前後でキャレット位置(選択範囲)に変化がないとき、
 *   または JSON ファイルに位置情報がないときは、
 *   キャレット位置にスクロールするだけ。
 * ⇒ さらに再実行すると選択範囲の先頭行が画面内の先頭になるようにスクロールする。
 * 
 * ・「位置を復帰」の動作では JSON ファイルに保存された位置情報を削除しない。
 *  ※ Ctrl キーを押しながらこのマクロを実行したとき、
 *     または「すべて選択」マクロ実行時の「位置情報を保存」処理のさいに、
 *     開かれていないファイルの位置情報は JSON から削除される。
 * 
 * ・このマクロで保存した位置情報を、当該ファイルのタブを閉じずに削除したい場合は、
 *   「すべて選択」マクロと「選択解除」マクロをつづけて実行する。
 *  ※「すべて選択」の状態から「選択解除」マクロを実行したとき(位置の復帰動作)
 *     当該ファイルの位置情報は JSON から削除される。
 *  ※ このマクロ単独で「位置情報を保存/位置を復帰」の運用をする場合、
 *     JSON から位置情報を削除するには、当該ファイルのタブを閉じた状態で
 *     別のタブ上から「位置情報を保存」操作をするしかない。
 */

メモ[編集]

  • (2020/11/01, sukemaru)
・画面の強制再描画によるチラツキを防ぐために、各ソースコード内の Redraw = false Redraw = true の処理をコメントアウトしました。
・Mery Ver 3.0.0 以降では Document.Tag プロパティを利用すれば複数の「無題-<n>」タブの位置情報を 個別 に保存/復帰できるのですが、その場合、タブの開きなおしや Mery の再起動で位置情報が消えてしまいます。
⇒ ワークスペース機能を利用している場合の利便性を優先するために、外部ファイル(JSON)を利用する仕様のままにしました。
・このマクロでは、Mery Ver 3.1.0 以降で [ウインドウの分割(上下/左右)] 機能を利用しているさいに、分割ペインごとの位置情報(選択範囲・スクロール状態)を 個別 に保存/復帰することはできません。
※ アクティブなエディターペイン上で動作するはずですが、Mery アルファ/ベータ版のバージョンごとの動作検証はしていません。
スポンサーリンク