位置情報を保存してから「次の文字列を検索」

提供: MeryWiki
移動先: 案内検索

概要[編集]

フォーラム

> 例えばですが、関数の使用箇所、関数の定義場所とかを行き来しているときに、
> 確かに、気軽にジャンプ前の箇所を探せると便利ですね。

という提案があったので、マクロにしてみました。

「次の文字列を検索」「前の文字列を検索」でジャンプする前の位置を外部 JSON ファイルに書き出して保存します(※要 「includeライブラリ」)。

  • 「位置情報を保存してから『次の文字列を検索』」
  • 「位置情報を保存してから『前の文字列を検索』」
  • 「保存された位置情報でジャンプ(復帰)」
のみっつのマクロでワンセットです。


ドキュメントごとの [ フルパス, 検索文字列, 位置(文書の先頭からの文字数), n件目, 行番号 ] を JSON ファイルに保存します(※「無題-x」のタブはファイルパスがないので区別できません)。
保存された位置よりも前(上)の文章を再編集・変更したばあい、復帰用のマクロが正しい位置を取得できなくなるので、あらかじめ ソースコード の設定項目で代替処理方法を指定してください。


  • 「次の文字列を検索」「前の文字列を検索」と同等の機能をふくんでいますが、ジャンプ前の位置情報を保存する必要があるときに使用するためのものです。
  • 「次の文字列を検索」「前の文字列を検索」とは別のショートカットキーを割り当てて使用してください。
  • すばやく連続で実行すると環境によっては JSON の読みこみ/書きこみ I/O でなんらかのエラーが発生するかもしれません。


位置情報の保存用ファイルの保存先は
・ポータブル版:  Mery\Macros\MacroSettings\FindRepeatInfo.json
・インストール版: %AppData%\Mery\MacroSettings\FindRepeatInfo.json


ダウンロード[編集]

ファイル:位置情報を保存してから「次/前の文字列を検索」.zip


ソースコード[編集]

位置情報を保存してから「次の文字列を検索」[編集]

#title = "位置情報を保存してから「次の文字列を検索」"
#tooltip = "ジャンプ前の位置情報を保存して「次の文字列を検索」する"
#include "include/IO.js"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",220

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

var findNext = true;
  // true   なら「次の文字列を検索(Shift+Ctrl+↓)」
  // false  なら「前の文字列を検索(Shift+Ctrl+↑)」

var optionEnable = true;
  // true  なら「次の文字列を検索(Shift+Ctrl+↓)」コマンドを利用してジャンプ
  //       ※検索ダイアログの「正規表現」以外のオプションが適用される
  // false なら FindRepeat() メソッドを利用してジャンプ
  //       ※検索オプションをリセット(すべて OFF )する
  //       ※検索ダイアログの履歴に残らない

var highlightEnable = true;
  // true  なら検索文字列の強調表示を残す
  // false なら「検索文字列の強調を解除(Alt+F3)」する

var jsonName = "FindRepeatInfo";
  // 位置情報保存用ファイルのベース名
  // ※「保存」マクロ(次/前の文字列を検索)と「復帰」マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "FindRepeatInfo" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\FindRepeatInfo.json
  // ・インストール版: %AppData%\Mery\MacroSettings\FindRepeatInfo.json

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

var setting = { fileList: [] }
setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み

var d = editor.ActiveDocument,  s = d.selection;
if ( s.IsEmpty ) { s.SelectWord(); }
var word = s.Text;
if ( ! word ) { Quit(); }
var path = d.FullName;	// 「無題-x」のタブは ""
var tx = s.GetActivePointY( mePosLogical );
var sy = ScrollY;

/* 検索開始時点の文字列の位置情報、ヒット件数 */
var wordPos = Math.min( s.GetAnchorPos(), s.GetActivePos() );
var HitStatus = function( docu, str, strPos ) {
  var len = str.length;
  var dText = docu.Text;
  var pos = 0,  hit = 0,  a = [ 0, 0 ];
  while ( pos >= 0 ) {
    pos = dText.indexOf( str, pos );
    if ( pos >= 0 ) {
      hit ++;
      if ( pos == strPos ) { a[0] = hit; }
      pos += len;
    }
  }
  a[1] =  hit;
  return a;
}
var hit = HitStatus( d, word, wordPos );
var hitCount = hit[0];
var hitTotal = hit[1];

if ( findNext ) { FindNextWord(); }
else            { FindPreviousWord(); }

/* 「次の文字列を検索」を実行 */
function FindNextWord() {
  if ( optionEnable ) {
    editor.ExecuteCommandByID( MEID_SEARCH_NEXT_WORD = 2136 );
  }
  else {
    s.Find( "", 0 );	// 検索オプションをリセット
    s.FindRepeat( meFindNext + meFindRepeatWord );
  }
}

/* 「前の文字列を検索」を実行 */
function FindPreviousWord() {
  if ( optionEnable ) {
    editor.ExecuteCommandByID( MEID_SEARCH_PREV_WORD = 2137 );
  }
  else {
    s.Find( "", 0 );	// 検索オプションをリセット
    s.FindRepeat( meFindPrevious + meFindRepeatWord );
  }
}

editor.ActiveDocument.HighlightFind = highlightEnable;
ScrollY = ( ScrollY == sy ) ? sy : s.GetActivePointY( mePosView );

/* フルパス、検索文字列、検索開始時点の文字列の位置、n件目、行番号 */
var list = setting.fileList;
var len = setting.fileList.length;
var infoExist = false;
for ( var i = 0; i < len; i ++ ) {
  if ( setting.fileList[i][0] == path ) {
    infoExist = true;
    setting.fileList[i] = [ path, word, wordPos, hitCount, tx ];
    break;
  }
}
if ( ! infoExist ) {
  setting.fileList.push( [ path, word, wordPos, hitCount, tx ] );
}
try {
  setting = IO.Serialize( setting, jsonName );	// JSON 書き込み
  Status = "  " + hitTotal + " 件中 " + hitCount + " 件目の \""
         + word + "\" の位置を保存しました。";
} catch(e) {
  Status = "  検索開始位置を保存できませんでした。";
}


位置情報を保存してから「前の文字列を検索」[編集]

#title = "位置情報を保存してから「前の文字列を検索」"
#tooltip = "ジャンプ前の位置情報を保存して「前の文字列を検索」する"
#include "include/IO.js"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",221

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

var findNext = false;
  // true   なら「次の文字列を検索(Shift+Ctrl+↓)」
  // false  なら「前の文字列を検索(Shift+Ctrl+↑)」

var optionEnable = true;
  // true  なら「次の文字列を検索(Shift+Ctrl+↓)」コマンドを利用してジャンプ
  //       ※検索ダイアログの「正規表現」以外のオプションが適用される
  // false なら FindRepeat() メソッドを利用してジャンプ
  //       ※検索オプションをリセット(すべて OFF )する
  //       ※検索ダイアログの履歴に残らない

var highlightEnable = true;
  // true  なら検索文字列の強調表示を残す
  // false なら「検索文字列の強調を解除(Alt+F3)」する

var jsonName = "FindRepeatInfo";
  // 位置情報保存用ファイルのベース名
  // ※「保存」マクロ(次/前の文字列を検索)と「復帰」マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "FindRepeatInfo" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\FindRepeatInfo.json
  // ・インストール版: %AppData%\Mery\MacroSettings\FindRepeatInfo.json

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

var setting = { fileList: [] }
setting = IO.Deserialize( setting, jsonName );	// JSON 読み込み

var d = editor.ActiveDocument,  s = d.selection;
if ( s.IsEmpty ) { s.SelectWord(); }
var word = s.Text;
if ( ! word ) { Quit(); }
var path = d.FullName;	// 「無題-x」のタブは ""
var tx = s.GetActivePointY( mePosLogical );
var sy = ScrollY;

/* 検索開始時点の文字列の位置情報、ヒット件数 */
var wordPos = Math.min( s.GetAnchorPos(), s.GetActivePos() );
var HitStatus = function( docu, str, strPos ) {
  var len = str.length;
  var dText = docu.Text;
  var pos = 0,  hit = 0,  a = [ 0, 0 ];
  while ( pos >= 0 ) {
    pos = dText.indexOf( str, pos );
    if ( pos >= 0 ) {
      hit ++;
      if ( pos == strPos ) { a[0] = hit; }
      pos += len;
    }
  }
  a[1] =  hit;
  return a;
}
var hit = HitStatus( d, word, wordPos );
var hitCount = hit[0];
var hitTotal = hit[1];

if ( findNext ) { FindNextWord(); }
else            { FindPreviousWord(); }

/* 「次の文字列を検索」を実行 */
function FindNextWord() {
  if ( optionEnable ) {
    editor.ExecuteCommandByID( MEID_SEARCH_NEXT_WORD = 2136 );
  }
  else {
    s.Find( "", 0 );	// 検索オプションをリセット
    s.FindRepeat( meFindNext + meFindRepeatWord );
  }
}

/* 「前の文字列を検索」を実行 */
function FindPreviousWord() {
  if ( optionEnable ) {
    editor.ExecuteCommandByID( MEID_SEARCH_PREV_WORD = 2137 );
  }
  else {
    s.Find( "", 0 );	// 検索オプションをリセット
    s.FindRepeat( meFindPrevious + meFindRepeatWord );
  }
}

editor.ActiveDocument.HighlightFind = highlightEnable;
ScrollY = ( ScrollY == sy ) ? sy : s.GetActivePointY( mePosView );

/* フルパス、検索文字列、検索開始時点の文字列の位置、n件目、行番号 */
var list = setting.fileList;
var len = setting.fileList.length;
var infoExist = false;
for ( var i = 0; i < len; i ++ ) {
  if ( setting.fileList[i][0] == path ) {
    infoExist = true;
    setting.fileList[i] = [ path, word, wordPos, hitCount, tx ];
    break;
  }
}
if ( ! infoExist ) {
  setting.fileList.push( [ path, word, wordPos, hitCount, tx ] );
}
try {
  setting = IO.Serialize( setting, jsonName );	// JSON 書き込み
  Status = "  " + hitTotal + " 件中 " + hitCount + " 件目の \""
         + word + "\" の位置を保存しました。";
} catch(e) {
  Status = "  検索開始位置を保存できませんでした。";
}


保存された位置情報でジャンプ(復帰)[編集]

#title = "保存された位置情報でジャンプ(復帰)"
#tooltip = "「次/前の文字列を検索」マクロで保存された位置に復帰する"
#include "include/IO.js"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",225

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

var altPos = true;
  // 「保存された位置」に「保存された文字列」がなかったときの代替処理方法
  // true  なら「保存された位置」に最寄の「保存された文字列」の位置にジャンプ
  // false なら「保存された文字列」があったはずの行番号にジャンプ

var jsonName = "FindRepeatInfo";
  // 位置情報保存用ファイルのベース名(初期値: "FindRepeatInfo")
  // ※「保存」マクロ(次/前の文字列を検索)と「復帰」マクロで同一の名前を指定すること
  // 保存先は…		(e.g. "FindRepeatInfo" の場合)
  // ・ポータブル版: Mery\Macros\MacroSettings\FindRepeatInfo.json
  // ・インストール版: %AppData%\Mery\MacroSettings\FindRepeatInfo.json

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

var setting = { fileList: [] }
setting = IO.Deserialize( setting, "FindRepeatInfo" );	// JSON 読み込み
var list = setting.fileList;
var len = list.length;
var d = editor.ActiveDocument,  s = d.selection;
var path = d.FullName;
var fileInfo;
for ( var i = 0; i < len; i ++ ) {
  /* fileList[i] = [ "フルパス"、"検索文字列"、文字列の位置、n件目、行番号 ] */
  fileInfo = setting.fileList[i];

  /* JSON に位置情報があれば… */
  if ( fileInfo[0] == path ) {
    var dt = d.Text,  word = fileInfo[1];  targetPos = fileInfo[2];
    len = word.length;

    /* ① 保存された「位置」に「文字列」がそのままあれば、そこにジャンプする */
    if ( dt.substr( targetPos ).indexOf( word ) == 0 ) {
      s.SetActivePos( targetPos );
      s.SetActivePos( targetPos + len, true );
      Status = "  保存された位置にジャンプ";
    }

    /* 保存された「位置」に保存した「文字列」がなければ… */
    else if ( altPos ) {
      /* ②-1 「n件目」の「文字列」を検索してジャンプする */
      var tmp = 0,  pos = 0,  hit = 0;
      while ( hit < fileInfo[3] ) {
        tmp = dt.indexOf( word, pos );
        if ( tmp == -1 ) { break; }
        else {
          pos = tmp + len;
          hit ++;
        }
      }
      if ( dt.substr( pos - len ).indexOf( word ) == 0 ) {
        s.SetActivePos( pos - len );
        s.SetAnchorPos( pos );
        Status = "  " + hit + " 件目の \"" + word + "\" の位置にジャンプ";
      }
      /* ③ 「n件目」にあたる「文字列」がなければ、さいごの「文字列」の位置にジャンプする */
      else if ( dt.lastIndexOf( word ) >= 0 ) {
        pos = dt.lastIndexOf( word );
        s.SetActivePos( pos );
        s.SetAnchorPos( pos + len );
        Status = "  さいごの \"" + word + "\" の位置にジャンプ";
      }
      /* ④ 文書全体に「保存された文字列」がなければジャンプしない */
      else {
        Status = "  \"" + word + "\" が見つかりませんでした。";
      }
    }

    /* ②-2 「保存された文字列」があったはずの行番号にジャンプする */
    else {
      s.SetActivePoint( mePosLogical, 1, fileInfo[4] );
      Status = "  保存された行番号にジャンプ";
    }

    break;
  }
}


メモ[編集]

「最後に編集した位置へ移動」バージョンもあったほうがいいのかしら?

  • 2019/05/28: 初版
スポンサーリンク