「ポップアップメニューで検索先にジャンプ」の版間の差分
→sukemaru 版: 人柱版を更新(第3版) |
→sukemaru 版: 通常版/人柱版ともに更新 |
||
| 63行目: | 63行目: | ||
ポップアップメニューを表示させるだけ(キャンセルする)であれば検索履歴には残らないようにしてありますので、検索ダイアログの最新の検索文字列を置きかえることなく、重複行の確認や選択文字列が出現する行の確認をできます。 | |||
※ ポップアップメニューは Esc キーでキャンセルできます。 <br> | ※ ポップアップメニューは Esc キーでキャンセルできます。 <br> | ||
| 70行目: | 69行目: | ||
== 変更点 == | == 変更点 == | ||
▼ 手石版からの変更点 ▼ | ▼ 手石版からの変更点 ▼ | ||
* エディタ設定の「行の表示方法」にあわせられるように、ポップアップメニューに表示する行番号は表示行/論理行を選択できます(■ソースコード内の変数で設定)。 | * エディタ設定の「行の表示方法」にあわせられるように、ポップアップメニューに表示する行番号は表示行/論理行を選択できます(■ソースコード内の変数で設定)。 | ||
| 76行目: | 76行目: | ||
* ヒットした行数や文書全体の行数をステータスバーに表示します。 | * ヒットした行数や文書全体の行数をステータスバーに表示します。 | ||
* 重複行のチェックをしやすくなるよう、論理行全体を範囲選択しているときは末尾改行を除外するようにしました。 | * 重複行のチェックをしやすくなるよう、論理行全体を範囲選択しているときは末尾改行を除外するようにしました。 | ||
* | * ポップアップメニューをキャンセルすればムダな検索履歴も残らないので、検索文字列の禁止文字条件をなくしました。 <br> | ||
※ 正規表現を使わずに行単位で検索するので、改行は末尾の "\n" ×1 以外ダメ(空行も不可)。 | ※ 正規表現を使わずに行単位で検索するので、改行は末尾の "\n" ×1 以外ダメ(空行も不可)。 | ||
▼ 人柱版から移植した追加機能 (2018/12/13) ▼ | |||
* 「検索処理の所要時間」をステータスバーに表示できます(◆ソースコード内の変数で設定)。 | |||
* キャンセルせずに検索ジャンプしたときにも検索文字列を検索/置換ダイアログの「検索履歴」に残さないようにできます(◆ソースコード内の変数で設定)。 <br> 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版の設定項目「■検索文字列の強調表示を残す」も無効になります。 | |||
* 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆ソースコード内の変数で設定) | |||
== ダウンロード (sukemaru 版) == | == ダウンロード (sukemaru 版) == | ||
ダウンロード: 「[[ファイル:ジャンプ.zip]] (アイコン入り)」 (2018/12/ | ダウンロード: 「[[ファイル:ジャンプ.zip]] (アイコン入り)」 (2018/12/13 更新) | ||
: 以下のマクロ4点と、それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱してあります。 <br> 「ジャンプ」の下の3点は[[マテリアルデザインっぽいアイコンと『小マクロ集』#メニュー項目をアイコン化する小マクロ|『小マクロ集』]]にソースコードを置いてあります。 | : 以下のマクロ4点と、それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱してあります。 <br> 「ジャンプ」の下の3点は[[マテリアルデザインっぽいアイコンと『小マクロ集』#メニュー項目をアイコン化する小マクロ|『小マクロ集』]]にソースコードを置いてあります。 | ||
:* ジャンプ(ポップアップメニューで検索先にジャンプ) <br> (※「[[#人柱版|人柱版]]」も同梱) | :* ジャンプ(ポップアップメニューで検索先にジャンプ) <br> (※「[[#人柱版|人柱版]]」も同梱) | ||
| 101行目: | 108行目: | ||
* Original Copyright: 手石 (2014/04/04) | * Original Copyright: 手石 (2014/04/04) | ||
* ------------------------------------------------------------ | * ------------------------------------------------------------ | ||
* Modified by: sukemaru (2018/11/12 - 2018/ | * Modified by: sukemaru (2018/11/12 - 2018/12/13) | ||
* ------------------------------------------------------------ | * ------------------------------------------------------------ | ||
*/ | */ | ||
var start = new Date().getTime(); // 所要時間の計測開始 | |||
// ■行の表示方法 (true; 論理座標 /false; 表示座標) | // ■行の表示方法 (true; 論理座標 /false; 表示座標) | ||
| 114行目: | 123行目: | ||
// ※ [表示]メニュー >> [マーカー] >> [自動マーカー] が ON でなければ効果なし | // ※ [表示]メニュー >> [マーカー] >> [自動マーカー] が ON でなければ効果なし | ||
var markerEnable = true; | var markerEnable = true; | ||
// ◆検索文字列を「検索履歴」に残さない? (true; 残さない / false; 残す) | |||
// ※ historyDisable = true の場合、通常版の設定 highliteEnable は無効になる(強調表示しない) | |||
var historyDisable = true; | |||
// ◆検索文字列の「大文字/小文字」を区別するか? (true; 区別する / false; 区別しない) | |||
var caseEnable = false; | |||
// ◆検索処理の所要時間を表示するか? (true; する /false; しない) | |||
var timerEnable = true; | |||
// ■ポップアップメニューに表示する文字数 | // ■ポップアップメニューに表示する文字数 | ||
var menuWidth = 66; | var menuWidth = 66; | ||
Redraw = markerEnable; | Redraw = markerEnable; | ||
var sx = ScrollX, sy = ScrollY; | var sx = ScrollX, sy = ScrollY; | ||
var d = document, s = document.selection; | var d = document, s = document.selection; | ||
if ( s.IsEmpty ) { | |||
var p = s.GetActivePos(); | // 論理行/表示行の設定を変数に | ||
var posMode = logical ? mePosLogical : mePosView; | |||
var lineMode = logical ? 0 : meGetLineView; | |||
// 選択範囲なしならカーソル位置の単語を選択 | |||
if ( s.IsEmpty ) { | |||
var p = s.GetActivePos(); // "選択範囲なし" フラグ | |||
s.SelectWord(); | s.SelectWord(); | ||
} | } | ||
| 129行目: | 157行目: | ||
if ( st.length > 1 && st.charAt( st.length - 1 ) == "\n" ) { | if ( st.length > 1 && st.charAt( st.length - 1 ) == "\n" ) { | ||
st = st.slice( 0, st.length - 1 ); | st = st.slice( 0, st.length - 1 ); | ||
var adjust = true; | // 自動マーカーを効かせるために選択範囲も調整する | ||
var anc = s.GetAnchorPos() | var adjust = true; // 調整フラグ | ||
var anc = s.GetAnchorPos(), act = s.GetActivePos(); | |||
if ( anc < act ) s.SetActivePos( act - 1, true ); | if ( anc < act ) { s.SetActivePos( act - 1, true ); } | ||
if ( act < anc ) s.SetAnchorPos( anc - 1 ) | if ( act < anc ) { s.SetAnchorPos( anc - 1 ); s.SetActivePos( act, true ); } | ||
} | } | ||
// 選択範囲の先頭と文書全体の行数(論理行/表示行) | // 選択範囲の先頭と文書全体の行数(論理行/表示行) | ||
var ty = | var ty = s.GetTopPointY( posMode ); | ||
var lines = d.GetLines( lineMode ); | |||
var lines = | |||
var cancel = 5; | var cancel = 5; | ||
if ( ! st ) cancel = 1; | if ( ! st ) cancel = 1; // 検索文字列がない(空行) | ||
else if ( st.match( /\n/g ) ) cancel = 2; // 検索条件エラー(改行) | else if ( st.match( /\n/g ) ) cancel = 2; // 検索条件エラー(改行) | ||
// ポップアップメニューでジャンプ先リスト | // ポップアップメニューでジャンプ先リスト | ||
else { | else { | ||
// 文書全体を行単位で分割して配列にする | // 文書全体を行単位で分割して配列にする | ||
for( var i = 1, a = [ "" ]; i <= lines ; i ++ ) | |||
a.push( d.GetLine( i, lineMode ) ); | |||
for( var i = | |||
a.push( d.GetLine( i, | |||
// 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する | // 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する | ||
var m = CreatePopupMenu(); | var m = CreatePopupMenu(); | ||
for( var i = 1, h = 0; i < a.length; i ++ ) { // a[0] = 空要素、i = 行番号 = y | |||
for( var i = 0; i < a.length; i ++ ) { // a[0] = 空要素、i = 行番号 = y | if ( findCaseTF( a[i], st ) >= 0 ) { | ||
if ( a[i] | |||
// 行頭空白は除去、空白文字は半角スペースに置換、文字数を圧縮して取得 | // 行頭空白は除去、空白文字は半角スペースに置換、文字数を圧縮して取得 | ||
var label = a[i].replace( /^\s+/, "" ).replace( /\t+|[ ]{3,}/g, " " ); | // 判別しづらい半角メタ文字を全角に置きかえる | ||
var label = a[i].replace( /^\s+/, "" ).replace( /\t+|[ ]{3,}/g, " " ) | |||
.replace( /[.,:;(){}]/g , | |||
function( $0 ) { return String.fromCharCode( $0.charCodeAt( 0 ) + 0xFEE0 ) } | |||
); | |||
label = ( label.length > menuWidth + 1 ) ? label.slice( 0, menuWidth ) + "..." : label; | label = ( label.length > menuWidth + 1 ) ? label.slice( 0, menuWidth ) + "..." : label; | ||
var flags = ( i == ty ) ? meMenuChecked : 0; // + meMenuGrayed | var flags = ( i == ty ) ? meMenuChecked : 0; // + meMenuGrayed | ||
m.Add( ( " " + i ).slice( -4 ) + " : " + label, i, flags ); | m.Add( ( " " + i ).slice( -4 ) + " : " + label, i, flags ); | ||
h ++; | h ++; // ヒットした行数 | ||
} | } | ||
} | } | ||
// 検索開始からポップアップメニューを表示するまでの所要時間を取得 | |||
if ( timerEnable ) { | |||
var elapsed = new Date().getTime() - start; | |||
var timerStatus = " [ " | |||
+ ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" ) | |||
+ " 秒 ]"; | |||
} | |||
// ポップアップメニューを表示するのは、検索ヒット行が複数のとき | // ポップアップメニューを表示するのは、検索ヒット行が複数のとき | ||
if ( h > 1 ) { | if ( h > 1 ) { | ||
Status = " ヒットした行数: " + SeparateNum( h ) + " 行" | Status = " ヒットした行数: " + SeparateNum( h ) + " 行" | ||
+ " / 全体の行数: " + SeparateNum( lines ) | + " / 全体の行数: " + SeparateNum( lines ) | ||
+ ( logical ? " 行 (論理行)" : " 行 (表示行)" ); | + ( logical ? " 行 (論理行)" : " 行 (表示行)" ) | ||
+ ( timerEnable ? timerStatus : "" ); | |||
var y = m.Track( mePosMouse ); // Track(0) ならキャレット位置にポップアップ | var y = m.Track( mePosMouse ); // Track(0) ならキャレット位置にポップアップ | ||
if ( y > 0 ) { | if ( y > 0 ) { | ||
// 選択した行番号にジャンプして検索文字列を選択 | // 選択した行番号にジャンプして検索文字列を選択 | ||
s.SetActivePoint( posMode, 1, y ); | |||
if ( historyDisable ) { | |||
s.Find( st, meFindNext ); | // 検索履歴に残さない ※「検索文字列の強調表示」なし | ||
s.SetActivePos( s.GetActivePos() + findCaseTF( d.GetLine( y, lineMode ), st ) ); | |||
cancel = 0; | s.SetAnchorPos( s.GetActivePos() + st.length ); | ||
} | |||
else { | |||
// 検索履歴に残す ※ Mery の検索機能で文字列を範囲選択 | |||
s.Find( st, meFindNext ); | |||
d.HighlightFind = highlightEnable; // 「検索文字列の強調表示」を解除する/しない | |||
} | |||
cancel = 0; // cancel フラグを解除 | |||
} | } | ||
else cancel = 3; // ポップアップメニューをキャンセル | else cancel = 3; // ポップアップメニューをキャンセル | ||
} | } | ||
else cancel = 4; | else cancel = 4; // ほかの行でヒットなし | ||
} | } | ||
// ジャンプしなかったとき | // ジャンプしなかったとき | ||
if ( cancel ) { | if ( cancel ) { | ||
| 191行目: | 235行目: | ||
else if ( adjust && anc < act ) s.SetActivePos( act, true ); | else if ( adjust && anc < act ) s.SetActivePos( act, true ); | ||
else if ( adjust && act < anc ) s.SetAnchorPos( anc ), s.SetActivePos( act, true ); | else if ( adjust && act < anc ) s.SetAnchorPos( anc ), s.SetActivePos( act, true ); | ||
// キャンセルフラグの値が 1 or 2 のとき、所要時間の計測終了 | |||
if ( timerEnable && ! elapsed ) { | |||
var elapsed = new Date().getTime() - start; | |||
var timerStatus = " [ " | |||
+ ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" ) | |||
+ " 秒 ]"; | |||
} | |||
Status = ( ( cancel == 1 ) ? " 検索文字列がありません(空行)。" : | Status = ( ( cancel == 1 ) ? " 検索文字列がありません(空行)。" : | ||
( cancel == 2 ) ? " 検索文字列に【 改行 】を含めることはできません。" : | ( cancel == 2 ) ? " 検索文字列に【 改行 】を含めることはできません。" : | ||
| 196行目: | 249行目: | ||
+ SeparateNum( h ) + " 行" : | + SeparateNum( h ) + " 行" : | ||
( cancel == 4 ) ? " ほかの行には見つかりませんでした。" : | ( cancel == 4 ) ? " ほかの行には見つかりませんでした。" : | ||
/* cancel == 5 */ " | /* cancel == 5 */ " 無効な検索文字列。" ) | ||
+ " / 全体の行数: " + SeparateNum( lines ) | + " / 全体の行数: " + SeparateNum( lines ) | ||
+ ( logical ? " 行 (論理行)" : " 行 (表示行)" ); | + ( logical ? " 行 (論理行)" : " 行 (表示行)" ) | ||
+ ( timerEnable ? timerStatus : "" ); | |||
ScrollX = sx; ScrollY = sy; | ScrollX = sx; ScrollY = sy; | ||
} | } | ||
Redraw = true; | Redraw = true; | ||
/* 関数 findCaseTF( str, st ) */ | |||
// 文字列 str 内で st を検索するさいに「大文字/小文字を区別」する/しない | |||
// ヒットすればヒットした位置( 0 ~ )、ヒットしなければ -1 を返す | |||
function findCaseTF( str, st ) { | |||
return caseEnable ? str.indexOf( st ) : | |||
/* else */ str.toLowerCase().indexOf( st.toLowerCase() ) | |||
} | |||
/* 関数 SeparateNum( num ) */ | |||
// 数値を3ケタ区切りにする | // 数値を3ケタ区切りにする | ||
function SeparateNum( num ) { | function SeparateNum( num ) { | ||
| 211行目: | 277行目: | ||
== 人柱版 == | == 人柱版 == | ||
「表示行」で運用した場合の '''動作検証が不十分''' ですが、以下の追加オプションにご興味のある方は [[#ダウンロード (sukemaru 版)|ZIP 書庫]] 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。 <br> | 「表示行」で運用した場合の '''動作検証が不十分''' ですが、以下の追加オプションにご興味のある方は [[#ダウンロード (sukemaru 版)|ZIP 書庫]] 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。 <br> | ||
動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。 | 動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。 | ||
▼ 追加オプション ▼ | ▼ 追加オプション ▼ | ||
* 「検索処理の所要時間」をステータスバーに表示します(◆変数で設定)。 | |||
:* 人柱版では処理が遅くなる追加機能が多いので…。 | |||
* 「行の表示方法」の設定を Mery.ini から自動取得するかしないかを選択できます(◆変数で設定)。 | |||
:* ただし、ini ファイルが肥大化またはフラグメントしていると、処理が多少遅くなります。 | |||
* 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。 | * 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。 | ||
:* 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。 | :* 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。 | ||
| 220行目: | 294行目: | ||
* 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。 | * 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。 | ||
* 空行にキャレットがある状態か、"末尾改行をふくめて" | * 空行にキャレットがある状態か、"末尾改行をふくめて" 空白行を範囲選択している状態から、「すべての空行+空白行」を検索できるオプションを追加しました(変数で設定)。 | ||
:* 「空行+空白行」オプションが有効 ( true ) の場合は、末尾改行 "\n" をふくめて「空白文字のみの行」を範囲選択しているときに、すべての「空行+空白行」を検索対象にします。末尾改行をふくめずに「空白文字のみの行」を範囲選択しているときは「一致する空白文字列」を検索対象にします。 | :* 「空行+空白行」オプションが有効 ( true ) の場合は、末尾改行 "\n" をふくめて「空白文字のみの行」を範囲選択しているときに、すべての「空行+空白行」を検索対象にします。末尾改行をふくめずに「空白文字のみの行」を範囲選択しているときは「一致する空白文字列」を検索対象にします。 | ||
| 229行目: | 303行目: | ||
* 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。 | * 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。 | ||
* 検索対象が「空行+空白行」でないとき、ポップアップメニューの右隅に以下のマーキングを表示できます(「ヒット件数」オプションが有効の場合のみ)。 | |||
:* JavaScript で検索文字列が変数/関数名のとき、定義行に「 ← var 」「 ← fn 」マーク | |||
:* 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク | :* 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク | ||
:* | :* アクティブ行と完全に一致する重複行に「 ** 」マーク (※行検索でないときにも表示) | ||
:* 検索文字列と完全に一致する行に「 * 」マーク | :* 検索文字列と完全に一致する行に「 * 」マーク | ||
:* 検索文字列が複数回ヒットした行に「 x2 」マーク | :* 検索文字列が複数回ヒットした行に「 x2 」マーク | ||
: | : ※「一致」の判定では、つねに大文字/小文字を区別します。 | ||
* ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。 | * ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。 | ||
※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。 <br> | ※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。 <br> | ||
※「人柱版 設定項目」の変数の値をすべて無効 false | ※「人柱版 設定項目」の変数の値をすべて無効 false にすれば通常版とほぼおなじ動作になります。 | ||
| 251行目: | 326行目: | ||
* (2018/11/12 sukemaru) | * (2018/11/12 sukemaru) | ||
: Get/SetActivePoint() や GetLines() のオプションパラメータ( mePosView や meGetLineView )を変数にすると機能しなくなるようで条件文 if ( logical ) や ( logical ) ? : をひとつひとつ書かかざるをえず、余計に長くなってしまいました。 | : Get/SetActivePoint() や GetLines() のオプションパラメータ( mePosView や meGetLineView )を変数にすると機能しなくなるようで条件文 if ( logical ) や ( logical ) ? : をひとつひとつ書かかざるをえず、余計に長くなってしまいました。 | ||
: → ちゃんと機能するようにできました。(2018/12/13) | |||
* (2018/11/14 sukemaru) | * (2018/11/14 sukemaru) | ||
: ・ZIP の「ジャンプ.js」がソースコードのものより古い版だったので差し替えました。 | : ・ZIP の「ジャンプ.js」がソースコードのものより古い版だったので差し替えました。 | ||
| 264行目: | 340行目: | ||
* (2018/12/10 sukemaru) | * (2018/12/10 sukemaru) | ||
: 論理行表示で「人柱版」を使っていますが、とくに問題なさそうです。<br>いまとなっては「通常版」が短いマクロであるかのように錯覚してしまいます。 | : 論理行表示で「人柱版」を使っていますが、とくに問題なさそうです。<br>いまとなっては「通常版」が短いマクロであるかのように錯覚してしまいます。 | ||
* (2018/12/13 sukemaru) | |||
: ・「人柱版」の追加機能のうち処理速度に影響しないものを選んで「通常版」に逆移植しました。 | |||
: ・「人柱版」のほうには Mery.ini から「行の表示方法」設定の読み込みを積めこみましたが、検索ダイアログの「大文字/小文字」オプションの変更は ini ファイルに即時反映されないため取り込む意味がなくて残念ながら不採用です。 | |||
2018年12月13日 (木) 20:55時点における版
概要
ポップアップメニューで検索にヒットした箇所へジャンプできます。
手石 版
機能
- 選択した文字列(選択していないときはカーソルのある語)を検索します。
- ヒットした行をポップアップメニューに表示し、選択するとその行へジャンプします。
- 同一行にヒットする箇所が複数あったときは最初のヒット箇所にジャンプします。
- 検索文字列の強調解除は、変更していなければ「Alt+F3」です。
コード (手石 版)
// pooupJump.js
// 2014/04/04
var sel = document.selection
if ( sel.isEmpty ){ sel.SelectWord(); };
var s = sel.Text;
var ty = sel.GetTopPointY( mePosView );
var p = sel.GetActivePos();
sel.Find( s, meFindNext + meFindAround );
sel.SetActivePos( p );
// ポップアップメニューでジャンプ先リスト
var menu_width = 66;
if ( "\t .,;:(){}[]+-=\"\\".indexOf( s ) < 0 && s.length > 0 ){
var menu = CreatePopupMenu();
var ary = [];
for( var i = 0, n = document.GetLines( meGetLineView ); i < n ; i++ ){
ary.push( document.GetLine( i+1, meGetLineView ));
};
var p = 0;
for( var i = 0, n = ary.length; i < n ; i++ ){
if ( ary[i].toLowerCase().indexOf( s.toLowerCase() ) >= 0 ){
var item = ary[i].replace( /^\s*|\t/g, "" )
item = ( item.length > menu_width + 1 )? item.slice( 0, menu_width ) + "..." : item ;
var flags = ( (i+1) == ty )? meMenuChecked : 0 ; // meMenuGrayed
menu.Add( ( " " + (i + 1) ).slice( -4 ) + " : " + item, i + 1, flags );
p++;
};
};
if ( p > 1 ){ // ポップアップメニューを表示するのは、検索ヒット行が複数のとき。
var r = menu.Track( mePosMouse ); // mePosMouse
if ( r > 0 ){
var line = document.GetLine( r, meGetLineView );
sel.SetActivePoint( mePosView, line.indexOf( s ) + s.length + 1, r, false );
sel.CharLeft( true, s.length );
ScrollY = r-10;
};
};
};
履歴
- 2014/04/04 初版
その他
- 不具合があったら教えていただけると幸いです。
sukemaru 版
手石版のソースコードをベースにして、自分好みにカスタマイズしました。手石版の機能にあげられている部分はそのまま踏襲・流用しています。
ポップアップメニューを表示させるだけ(キャンセルする)であれば検索履歴には残らないようにしてありますので、検索ダイアログの最新の検索文字列を置きかえることなく、重複行の確認や選択文字列が出現する行の確認をできます。
※ ポップアップメニューは Esc キーでキャンセルできます。
※「行の表示方法」オプションが "false" (表示座標 = 表示行)で、折り返しにより検索文字列が途切れている場合はヒットしません(Mery 標準の検索ダイアログでは検出できるのですが…)。
変更点
▼ 手石版からの変更点 ▼
- エディタ設定の「行の表示方法」にあわせられるように、ポップアップメニューに表示する行番号は表示行/論理行を選択できます(■ソースコード内の変数で設定)。
- 検索文字列がほかの行でヒットしなかった場合や、ポップアップメニューからジャンプしなかった(キャンセル)場合に、検索履歴に残さないようにしました。
そのさい、マクロの実行前に選択範囲なしだったときは単語選択もキャンセルします。 - 検索文字列の強調表示を解除できます(■ソースコード内の変数で設定)。
- ヒットした行数や文書全体の行数をステータスバーに表示します。
- 重複行のチェックをしやすくなるよう、論理行全体を範囲選択しているときは末尾改行を除外するようにしました。
- ポップアップメニューをキャンセルすればムダな検索履歴も残らないので、検索文字列の禁止文字条件をなくしました。
※ 正規表現を使わずに行単位で検索するので、改行は末尾の "\n" ×1 以外ダメ(空行も不可)。
▼ 人柱版から移植した追加機能 (2018/12/13) ▼
- 「検索処理の所要時間」をステータスバーに表示できます(◆ソースコード内の変数で設定)。
- キャンセルせずに検索ジャンプしたときにも検索文字列を検索/置換ダイアログの「検索履歴」に残さないようにできます(◆ソースコード内の変数で設定)。
「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版の設定項目「■検索文字列の強調表示を残す」も無効になります。 - 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆ソースコード内の変数で設定)
ダウンロード (sukemaru 版)
ダウンロード: 「ファイル:ジャンプ.zip (アイコン入り)」 (2018/12/13 更新)
- 以下のマクロ4点と、それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱してあります。
「ジャンプ」の下の3点は『小マクロ集』にソースコードを置いてあります。
コード (sukemaru 版)
#title = "ジャンプ"
#tooltip = "ポップアップメニューで検索先にジャンプ"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",229
/**
* ------------------------------------------------------------
* "ポップアップメニューで検索先にジャンプ"
* pooupJump.js
* Original Copyright: 手石 (2014/04/04)
* ------------------------------------------------------------
* Modified by: sukemaru (2018/11/12 - 2018/12/13)
* ------------------------------------------------------------
*/
var start = new Date().getTime(); // 所要時間の計測開始
// ■行の表示方法 (true; 論理座標 /false; 表示座標)
var logical = true;
// ■検索文字列の強調表示を残すか? (true; 残す /false; 残さない)
var highlightEnable = true;
// ■選択範囲なしの状態から実行したときに自動マーカーを表示するか? (true; 表示する / false; 表示しない)
// ※ [表示]メニュー >> [マーカー] >> [自動マーカー] が ON でなければ効果なし
var markerEnable = true;
// ◆検索文字列を「検索履歴」に残さない? (true; 残さない / false; 残す)
// ※ historyDisable = true の場合、通常版の設定 highliteEnable は無効になる(強調表示しない)
var historyDisable = true;
// ◆検索文字列の「大文字/小文字」を区別するか? (true; 区別する / false; 区別しない)
var caseEnable = false;
// ◆検索処理の所要時間を表示するか? (true; する /false; しない)
var timerEnable = true;
// ■ポップアップメニューに表示する文字数
var menuWidth = 66;
Redraw = markerEnable;
var sx = ScrollX, sy = ScrollY;
var d = document, s = document.selection;
// 論理行/表示行の設定を変数に
var posMode = logical ? mePosLogical : mePosView;
var lineMode = logical ? 0 : meGetLineView;
// 選択範囲なしならカーソル位置の単語を選択
if ( s.IsEmpty ) {
var p = s.GetActivePos(); // "選択範囲なし" フラグ
s.SelectWord();
}
var st = s.Text; // 検索文字列
// 選択範囲の末尾が改行 "\n" なら検索文字列から除外する
if ( st.length > 1 && st.charAt( st.length - 1 ) == "\n" ) {
st = st.slice( 0, st.length - 1 );
// 自動マーカーを効かせるために選択範囲も調整する
var adjust = true; // 調整フラグ
var anc = s.GetAnchorPos(), act = s.GetActivePos();
if ( anc < act ) { s.SetActivePos( act - 1, true ); }
if ( act < anc ) { s.SetAnchorPos( anc - 1 ); s.SetActivePos( act, true ); }
}
// 選択範囲の先頭と文書全体の行数(論理行/表示行)
var ty = s.GetTopPointY( posMode );
var lines = d.GetLines( lineMode );
var cancel = 5;
if ( ! st ) cancel = 1; // 検索文字列がない(空行)
else if ( st.match( /\n/g ) ) cancel = 2; // 検索条件エラー(改行)
// ポップアップメニューでジャンプ先リスト
else {
// 文書全体を行単位で分割して配列にする
for( var i = 1, a = [ "" ]; i <= lines ; i ++ )
a.push( d.GetLine( i, lineMode ) );
// 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する
var m = CreatePopupMenu();
for( var i = 1, h = 0; i < a.length; i ++ ) { // a[0] = 空要素、i = 行番号 = y
if ( findCaseTF( a[i], st ) >= 0 ) {
// 行頭空白は除去、空白文字は半角スペースに置換、文字数を圧縮して取得
// 判別しづらい半角メタ文字を全角に置きかえる
var label = a[i].replace( /^\s+/, "" ).replace( /\t+|[ ]{3,}/g, " " )
.replace( /[.,:;(){}]/g ,
function( $0 ) { return String.fromCharCode( $0.charCodeAt( 0 ) + 0xFEE0 ) }
);
label = ( label.length > menuWidth + 1 ) ? label.slice( 0, menuWidth ) + "..." : label;
var flags = ( i == ty ) ? meMenuChecked : 0; // + meMenuGrayed
m.Add( ( " " + i ).slice( -4 ) + " : " + label, i, flags );
h ++; // ヒットした行数
}
}
// 検索開始からポップアップメニューを表示するまでの所要時間を取得
if ( timerEnable ) {
var elapsed = new Date().getTime() - start;
var timerStatus = " [ "
+ ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" )
+ " 秒 ]";
}
// ポップアップメニューを表示するのは、検索ヒット行が複数のとき
if ( h > 1 ) {
Status = " ヒットした行数: " + SeparateNum( h ) + " 行"
+ " / 全体の行数: " + SeparateNum( lines )
+ ( logical ? " 行 (論理行)" : " 行 (表示行)" )
+ ( timerEnable ? timerStatus : "" );
var y = m.Track( mePosMouse ); // Track(0) ならキャレット位置にポップアップ
if ( y > 0 ) {
// 選択した行番号にジャンプして検索文字列を選択
s.SetActivePoint( posMode, 1, y );
if ( historyDisable ) {
// 検索履歴に残さない ※「検索文字列の強調表示」なし
s.SetActivePos( s.GetActivePos() + findCaseTF( d.GetLine( y, lineMode ), st ) );
s.SetAnchorPos( s.GetActivePos() + st.length );
}
else {
// 検索履歴に残す ※ Mery の検索機能で文字列を範囲選択
s.Find( st, meFindNext );
d.HighlightFind = highlightEnable; // 「検索文字列の強調表示」を解除する/しない
}
cancel = 0; // cancel フラグを解除
}
else cancel = 3; // ポップアップメニューをキャンセル
}
else cancel = 4; // ほかの行でヒットなし
}
// ジャンプしなかったとき
if ( cancel ) {
if ( p ) s.SetActivePos( p );
else if ( adjust && anc < act ) s.SetActivePos( act, true );
else if ( adjust && act < anc ) s.SetAnchorPos( anc ), s.SetActivePos( act, true );
// キャンセルフラグの値が 1 or 2 のとき、所要時間の計測終了
if ( timerEnable && ! elapsed ) {
var elapsed = new Date().getTime() - start;
var timerStatus = " [ "
+ ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" )
+ " 秒 ]";
}
Status = ( ( cancel == 1 ) ? " 検索文字列がありません(空行)。" :
( cancel == 2 ) ? " 検索文字列に【 改行 】を含めることはできません。" :
( cancel == 3 ) ? " 検索ジャンプをキャンセルしました。 ヒット: "
+ SeparateNum( h ) + " 行" :
( cancel == 4 ) ? " ほかの行には見つかりませんでした。" :
/* cancel == 5 */ " 無効な検索文字列。" )
+ " / 全体の行数: " + SeparateNum( lines )
+ ( logical ? " 行 (論理行)" : " 行 (表示行)" )
+ ( timerEnable ? timerStatus : "" );
ScrollX = sx; ScrollY = sy;
}
Redraw = true;
/* 関数 findCaseTF( str, st ) */
// 文字列 str 内で st を検索するさいに「大文字/小文字を区別」する/しない
// ヒットすればヒットした位置( 0 ~ )、ヒットしなければ -1 を返す
function findCaseTF( str, st ) {
return caseEnable ? str.indexOf( st ) :
/* else */ str.toLowerCase().indexOf( st.toLowerCase() )
}
/* 関数 SeparateNum( num ) */
// 数値を3ケタ区切りにする
function SeparateNum( num ) {
return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," )
}
人柱版
「表示行」で運用した場合の 動作検証が不十分 ですが、以下の追加オプションにご興味のある方は ZIP 書庫 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。
動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。
▼ 追加オプション ▼
- 「検索処理の所要時間」をステータスバーに表示します(◆変数で設定)。
- 人柱版では処理が遅くなる追加機能が多いので…。
- 「行の表示方法」の設定を Mery.ini から自動取得するかしないかを選択できます(◆変数で設定)。
- ただし、ini ファイルが肥大化またはフラグメントしていると、処理が多少遅くなります。
- 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。
- 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。
- 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。
- 空行にキャレットがある状態か、"末尾改行をふくめて" 空白行を範囲選択している状態から、「すべての空行+空白行」を検索できるオプションを追加しました(変数で設定)。
- 「空行+空白行」オプションが有効 ( true ) の場合は、末尾改行 "\n" をふくめて「空白文字のみの行」を範囲選択しているときに、すべての「空行+空白行」を検索対象にします。末尾改行をふくめずに「空白文字のみの行」を範囲選択しているときは「一致する空白文字列」を検索対象にします。
- 「空行+空白行」オプションが無効 ( false ) の場合、空白文字のみの行」を範囲選択しているときには「一致する空白文字列」を検索対象にします。空行で実行した場合にはポップアップメニューは表示されません。
- ※「空行+空白行」が対象のとき以外は正規表現を使わずに行単位で検索するので、選択範囲が複数行(末尾以外に改行 "\n" がある)の場合や、空白行オプションが無効で選択範囲が空行 "^\n" の場合は検索できません。
- 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。
- 検索対象が「空行+空白行」でないとき、ポップアップメニューの右隅に以下のマーキングを表示できます(「ヒット件数」オプションが有効の場合のみ)。
- JavaScript で検索文字列が変数/関数名のとき、定義行に「 ← var 」「 ← fn 」マーク
- 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク
- アクティブ行と完全に一致する重複行に「 ** 」マーク (※行検索でないときにも表示)
- 検索文字列と完全に一致する行に「 * 」マーク
- 検索文字列が複数回ヒットした行に「 x2 」マーク
- ※「一致」の判定では、つねに大文字/小文字を区別します。
- ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。
※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。
※「人柱版 設定項目」の変数の値をすべて無効 false にすれば通常版とほぼおなじ動作になります。
人柱版のソースコード
メモ
- (2018/11/12 sukemaru)
- Get/SetActivePoint() や GetLines() のオプションパラメータ( mePosView や meGetLineView )を変数にすると機能しなくなるようで条件文 if ( logical ) や ( logical ) ? : をひとつひとつ書かかざるをえず、余計に長くなってしまいました。
- → ちゃんと機能するようにできました。(2018/12/13)
- (2018/11/14 sukemaru)
- ・ZIP の「ジャンプ.js」がソースコードのものより古い版だったので差し替えました。
- ・11/12 のソースコードでは表示行だと最終行を取得しなかったので修正しました。
- (2018/11/19 sukemaru)
- ヒット数や行数を表示する機能をつけてから、ムダに利用頻度があがった気がします。
- (2018/11/21 sukemaru)
- むしろジャンプしないほうが便利な? 検索ポップアップメニューになりました。
- (2018/11/23 sukemaru)
- 空行を数えられます…。
- (2018/11/25 sukemaru)
- 重いです。
- (2018/12/10 sukemaru)
- 論理行表示で「人柱版」を使っていますが、とくに問題なさそうです。
いまとなっては「通常版」が短いマクロであるかのように錯覚してしまいます。
- (2018/12/13 sukemaru)
- ・「人柱版」の追加機能のうち処理速度に影響しないものを選んで「通常版」に逆移植しました。
- ・「人柱版」のほうには Mery.ini から「行の表示方法」設定の読み込みを積めこみましたが、検索ダイアログの「大文字/小文字」オプションの変更は ini ファイルに即時反映されないため取り込む意味がなくて残念ながら不採用です。