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

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

すべて選択 (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 アルファ/ベータ版のバージョンごとの動作検証はしていません。
スポンサーリンク