「検索ジャンプの人柱版」の版間の差分
ナビゲーションに移動
検索に移動
細 →ソースコード |
更新 |
||
| 4行目: | 4行目: | ||
== 人柱版 == | == 人柱版 == | ||
「表示行」で運用した場合の '''動作検証が不十分''' ですが、以下の追加オプションにご興味のある方は [[#ダウンロード (sukemaru 版)|ZIP 書庫]] 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。 <br> | 「表示行」で運用した場合の '''動作検証が不十分''' ですが、以下の追加オプションにご興味のある方は [[#ダウンロード (sukemaru 版)|ZIP 書庫]] 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。 <br> | ||
動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。 | 動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。 | ||
▼ 追加オプション ▼ | ▼ 追加オプション ▼ | ||
* 「検索処理の所要時間」をステータスバーに表示します(◆変数で設定)。 | |||
:* 人柱版では処理が遅くなる追加機能が多いので…。 | |||
* 「行の表示方法」の設定を Mery.ini から自動取得するかしないかを選択できます(◆変数で設定)。 | |||
:* ただし、ini ファイルが肥大化またはフラグメントしていると、処理が多少遅くなります。 | |||
* 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。 | * 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。 | ||
:* 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。 | :* 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。 | ||
* 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。 | * 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。 | ||
* 空行にキャレットがある状態か、"末尾改行をふくめて" 空白行を範囲選択している状態から、「すべての空行+空白行」を検索できるオプションを追加しました(変数で設定)。 | * 空行にキャレットがある状態か、"末尾改行をふくめて" 空白行を範囲選択している状態から、「すべての空行+空白行」を検索できるオプションを追加しました(変数で設定)。 | ||
| 20行目: | 32行目: | ||
: ※「空行+空白行」が対象のとき以外は正規表現を使わずに行単位で検索するので、選択範囲が複数行(末尾以外に改行 "\n" がある)の場合や、空白行オプションが無効で選択範囲が空行 "^\n" の場合は検索できません。 | : ※「空行+空白行」が対象のとき以外は正規表現を使わずに行単位で検索するので、選択範囲が複数行(末尾以外に改行 "\n" がある)の場合や、空白行オプションが無効で選択範囲が空行 "^\n" の場合は検索できません。 | ||
* 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。 | * 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。 | ||
* 検索対象が「空行+空白行」でないとき、ポップアップメニューの右隅に以下のマーキングを表示できます(「ヒット件数」オプションが有効の場合のみ)。 | * 検索対象が「空行+空白行」でないとき、ポップアップメニューの右隅に以下のマーキングを表示できます(「ヒット件数」オプションが有効の場合のみ)。 | ||
:* JavaScript で検索文字列が変数/関数名のとき、定義行に「 ← var 」「 ← fn 」マーク | |||
:* 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク | :* 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク | ||
:* アクティブ行と完全に一致する重複行に「 ** 」マーク (※行検索でないときにも表示) | :* アクティブ行と完全に一致する重複行に「 ** 」マーク (※行検索でないときにも表示) | ||
| 30行目: | 45行目: | ||
:* 検索文字列が複数回ヒットした行に「 x2 」マーク | :* 検索文字列が複数回ヒットした行に「 x2 」マーク | ||
: ※「一致」の判定では、つねに大文字/小文字を区別します。 | : ※「一致」の判定では、つねに大文字/小文字を区別します。 | ||
* ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。 | * ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。 | ||
※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。 <br> | ※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。 <br> | ||
※「人柱版 設定項目」の変数の値をすべて無効 false | ※「人柱版 設定項目」の変数の値をすべて無効 false にすれば通常版とほぼおなじ動作になります。 | ||
[[ポップアップメニューで検索先にジャンプ#人柱版のソースコード|>> もとのページ]] | [[ポップアップメニューで検索先にジャンプ#人柱版のソースコード|>> もとのページ]] | ||
== ソースコード == | == ソースコード == | ||
<source lang="javascript"> | <source lang="javascript" style="height:40em; overflow:auto;"> | ||
#title = "ジャンプ" | #title = "ジャンプ" | ||
#tooltip = "ポップアップメニューで検索先にジャンプ" | #tooltip = "ポップアップメニューで検索先にジャンプ" | ||
| 46行目: | 64行目: | ||
// 「空行+空白行」の検索に対応 | // 「空行+空白行」の検索に対応 | ||
// 「ヒット件数(出現回数)」を表示 | // 「ヒット件数(出現回数)」を表示 | ||
// | // スペースキーでポップアップメニューをキャンセル可 | ||
// 「検索履歴に残さない」を追加(■通常版へ逆移植済み) | |||
// 「行の表示方法」を Mery.ini から取得 | |||
// 「自動マーカー」オプションを廃止(デフォルト: 自動マーカー有効) | |||
// 「検索所要時間」の表示(■通常版へ逆移植済み) | |||
// 検索ジャンプ後のスクロールの挙動を調整(■通常版へ逆移植済み) | |||
// 「変数/関数の定義行」のマーキング | |||
/** | /** | ||
| 54行目: | 78行目: | ||
* Original Copyright: 手石 (2014/04/04) | * Original Copyright: 手石 (2014/04/04) | ||
* ------------------------------------------------------------ | * ------------------------------------------------------------ | ||
* Modified by: sukemaru (2018/11/12 - 2018/12/ | * Modified by: sukemaru (2018/11/12 - 2018/12/13) | ||
* ------------------------------------------------------------ | * ------------------------------------------------------------ | ||
*/ | */ | ||
var start = new Date().getTime(); // 所要時間の計測開始 | |||
// ---------- ▼ 通常版 設定項目 ▼ ---------- | // ---------- ▼ 通常版 設定項目 ▼ ---------- | ||
// ■行の表示方法 (true; 論理座標 /false; 表示座標) | // ■行の表示方法 (true; 論理座標 /false; 表示座標) | ||
// ※ ◆人柱版◆ の追加設定で autoLineModeEnable = true の場合は無効(自動設定) | |||
var logical = true; // ■初期値 = true; (論理座標) | var logical = true; // ■初期値 = true; (論理座標) | ||
// ■検索文字列の強調表示を残すか? (true; 残す /false; 残さない) | // ■検索文字列の強調表示を残すか? (true; 残す /false; 残さない) | ||
var highlightEnable = | // ※ ◆人柱版◆ の追加設定で historyDisable = true の場合は無効(強調表示しない) | ||
var highlightEnable = false; // ■初期値 = true; (残す) | |||
// ---------- ▼ 人柱版 設定項目 ▼ ---------- | // ---------- ▼ 人柱版 設定項目 ▼ ---------- | ||
// | // ◆人柱版のオプションを有効にすると処理が遅くなります | ||
// ◆検索処理の所要時間を表示するか? (true; する /false; しない) | |||
var timerEnable = true; // ◆初期値 = true; (する) | |||
// ◆行の表示方法を Mery.ini から自動で読み込むか? (true; 読み込む /false; 読み込まない) | |||
// ※ ini ファイルが肥大化またはフラグメントしていると処理が遅くなる | |||
var autoLineModeEnable = true; // ◆初期値 = false; (読み込まない) | |||
// ◆検索文字列を「検索履歴」に残さない? (true; 残さない / false; 残す) | // ◆検索文字列を「検索履歴」に残さない? (true; 残さない / false; 残す) | ||
| 85行目: | 118行目: | ||
// ◆ヒット件数(出現回数)を表示するか? (true; する /false; しない) | // ◆ヒット件数(出現回数)を表示するか? (true; する /false; しない) | ||
var countEnable = true; // ◆初期値 = true; (する) | var countEnable = true; // ◆初期値 = true; (する) | ||
// ---------- ▼ 手石版 設定項目 ▼ ---------- | // ---------- ▼ 手石版 設定項目 ▼ ---------- | ||
| 93行目: | 127行目: | ||
// ---------- ▲ 設定項目 ここまで ▲ ---------- | // ---------- ▲ 設定項目 ここまで ▲ ---------- | ||
/* ■ポップアップメニューの「行番号の表示方法」 */ | |||
var $LineColumnView = logical ? 0 : 1; | |||
// Mery.ini から「行の表示方法」を取得する | |||
if (autoLineModeEnable ) { | |||
var WshShell = new ActiveXObject( "WScript.Shell" ); | |||
var Fso = new ActiveXObject( "Scripting.FileSystemObject" ); | |||
// ini を探す(Zip版なら Mery.exe のフォルダ、インストーラ版なら %appdata%\Mery フォルダ) | |||
var portableIni = editor.FullName.slice( 0, 0 - "mery.exe".length ) + "Mery.ini"; | |||
var iniPath = Fso.FileExists( portableIni ) ? portableIni : | |||
WshShell.ExpandEnvironmentStrings( "%APPDATA%\\Mery\\Mery.ini" ); | |||
var iniFile = Fso.OpenTextFile( iniPath, 1 ); | |||
var iniText = iniFile.ReadAll(); | |||
$LineColumnView = Number( iniText.match( /^LineColumnView=[01]$/m ).shift().slice( -1 ) ); | |||
iniFile.Close(); | |||
} | |||
// ini から取得した設定値にもとづいて変数に | |||
var posMode = $LineColumnView ? mePosView : mePosLogical; | |||
var lineMode = $LineColumnView ? meGetLineView : 0; | |||
var d = document, s = document.selection; | |||
var sx = ScrollX, sy = ScrollY; | var sx = ScrollX, sy = ScrollY; | ||
var | |||
// 選択範囲の先頭位置(行番号)と、文書全体の行数(論理行/表示行) | |||
var ty = s.GetTopPointY( posMode ); | |||
var lines = d.GetLines( lineMode ); | |||
/* 検索文字列の準備 */ | /* 検索文字列の準備 */ | ||
var blank = new RegExp( "^[\t ]*$" , "" ); // 空白行の正規表現 | var blank = new RegExp( "^[\t ]*$" , "" ); // 空白行の正規表現 | ||
var re; // "空白行の正規表現検索" フラグ | |||
// 選択範囲なしならキャレット位置の単語を選択する | // 選択範囲なしならキャレット位置の単語を選択する | ||
if ( s.IsEmpty ) { | if ( s.IsEmpty ) { | ||
| 119行目: | 181行目: | ||
} | } | ||
if ( blankEnable && st.match( blank ) ) | if ( blankEnable && st.match( blank ) ) | ||
re = true; // "空白行の正規表現検索" フラグ | |||
} | } | ||
// 文書末尾の空白行の場合でも "空白行の正規表現検索" フラグ | |||
else if ( blankEnable && st.match( blank ) && st == d.GetLine( ty, lineMode ) ) | |||
re = true; | |||
var cancel = 5; // "キャンセル" フラグ | var cancel = 5; // "キャンセル" フラグ | ||
| 133行目: | 195行目: | ||
else if ( st.match( /\n/g ) ) | else if ( st.match( /\n/g ) ) | ||
cancel = 2; | cancel = 2; | ||
// ポップアップメニューでジャンプ先リスト | // ポップアップメニューでジャンプ先リスト | ||
| 138行目: | 201行目: | ||
/* 文書全体を行単位で分割し、配列に */ | /* 文書全体を行単位で分割し、配列に */ | ||
for( var a = [ "" ], i = 1; i <= lines ; i ++ ) // a[0] = "" / i = 行番号 | |||
a.push( d.GetLine( i, lineMode ) ); | |||
/* | |||
/* ポップアップメニューの準備 */ | |||
var m = CreatePopupMenu(); | var m = CreatePopupMenu(); | ||
// | // 「文字列」の検索では先頭に「キャンセル」のアイテムを表示 | ||
if ( ! re ) { | if ( ! re ) { | ||
m.Add( " キャンセル & ", 0 ); | m.Add( " キャンセル & ", 0 ); // Space キーでキャンセル可 | ||
m.Add( "", 0, meMenuSeparator ); | m.Add( "", 0, meMenuSeparator ); | ||
// Grand total, Hit | // Grand total, Hit, Variables | ||
var gt = 0, | var mArray = [], t, gt = 0, hit = 0, v = 0, check = "", flags; | ||
// アクティブ行(検索開始行)全体の文字列を取得 | // アクティブ行(検索開始行)全体の文字列を取得 | ||
if ( countEnable ) | if ( countEnable ) | ||
var activeLine = d.GetLine( ty, | var activeLine = d.GetLine( ty, lineMode ); | ||
} | } | ||
// | // 「空行+空白行」の検索ではパターンごとの配列を使用する | ||
else { | else { | ||
var hArray = [], nArray = [], wArray = []; | var hArray = [], nArray = [], wArray = []; | ||
// Hit ( match completely ), Blank line ( n + w ), New line (^$), White space (^\ | // Hit ( match completely ), Blank line ( n + w ), New line ( ^$ ), White space ( ^[\s ]+$ ) | ||
var h = 0, b = 0, n = 0, w = 0; | var h = 0, b = 0, n = 0, w = 0; | ||
} | } | ||
/* 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する */ | /* 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する */ | ||
for( var i = 1; i < a.length; i ++ ) { // | var stQuote = st.replace( /\W/g , "\\$&" ); | ||
var reg = new RegExp( stQuote , caseEnable ? "g" : "gi" ); | |||
for( var i = 1; i < a.length; i ++ ) { // a[0] = 空要素、i = 行番号 => y | |||
// 空行からの検索なら「空行+空白行」以外はスキップ | // 空行からの検索なら「空行+空白行」以外はスキップ | ||
if ( re && ! a[i].match( blank ) ) | if ( re && ! a[i].match( blank ) ) | ||
continue; | continue; | ||
// | // 「検索文字列」がヒットしたら | ||
if ( ( ! re && findCaseTF( a[i], st ) >= 0 ) || ( re && a[i].match( blank ) ) ) { | if ( ( ! re && findCaseTF( a[i], st ) >= 0 ) || ( re && a[i].match( blank ) ) ) { | ||
// 行内でのヒット回数 | // 行内でのヒット回数 | ||
if ( ! re && countEnable ) { | if ( ! re && countEnable ) { | ||
t = a[i].match( reg ); | |||
gt += t.length; // 総ヒット回数(大文字/小文字を区別できる) | gt += t.length; // 総ヒット回数(大文字/小文字を区別できる) | ||
check = Marking(); // 右側につけるマーキング | |||
} | } | ||
// アクティブ行は左に ✓ チェックマーク付き | // アクティブ行は左に ✓ チェックマーク付き | ||
flags = ( i == ty ) ? meMenuChecked : 0; // + meMenuGrayed | |||
/* ポップアップメニューにアイテム(行)を追加する */ | /* ポップアップメニューにアイテム(行)を追加する */ | ||
// 「文字列」の検索では、行頭空白を除去、空白文字を半角スペースに置換、文字数を圧縮 | |||
if ( ! re ) { | if ( ! re ) { | ||
// | // 変数/関数の定義行はメニューの先頭にも置く | ||
m.Add( Labeling( a[i], i ) + check, i, flags ); | if ( countEnable && check.match( /←/ ) ) { | ||
m.Add( Labeling( a[i], i ) + check, i, flags ); | |||
v ++; | |||
} | |||
// 「検索文字列がヒットした行」を配列に格納 | |||
mArray.push( [ Labeling( a[i], i ) + check, i, flags ] ); // ヒットした行 | |||
hit ++; // ヒットした行数 | |||
} | } | ||
// 「空行+空白行」の検索ではサブメニュー用の配列に分別 | // 「空行+空白行」の検索ではサブメニュー用の配列に分別 | ||
else { // if ( re ) | else { // if ( re ) | ||
b ++; // | b ++; // 空行+空白行の総数 | ||
if ( a[i] == st ) { | if ( a[i] == st ) { | ||
hArray.push( [ Labeling( a[i], i ) | hArray.push( [ Labeling( a[i], i ), i, flags ] ); // 一致した行 | ||
h ++; // 一致した行数 | h ++; // 一致した行数 | ||
} | } | ||
if ( st && a[i] | if ( st && ! a[i] ) { | ||
nArray.push( [ Labeling( a[i], i ) | nArray.push( [ Labeling( a[i], i ), i, flags ] ); // 空行 | ||
n ++; // 空行数 | n ++; // 空行数 | ||
} | } | ||
else if ( a[i] | else if ( a[i] ) { | ||
wArray.push( [ Labeling( a[i], i ) | wArray.push( [ Labeling( a[i], i ), i, flags ] ); // 空白行 | ||
w ++; // 空白行数 | w ++; // 空白行数 | ||
} | } | ||
} | } | ||
} // end if{ 検索文字列がヒットしたら } | } // end if () { 検索文字列がヒットしたら } | ||
} // end for( ヒットした行を取得する ) | } // end for () { ヒットした行を取得する } | ||
// 配列から「検索文字列がヒットした行」をポップアップメニューに追加する | |||
if ( ! re && hit ) { | |||
if ( v ) | |||
m.Add( "", 0, meMenuSeparator ); | |||
for ( var i = 0; i < hit; i ++ ) { | |||
// 30件ごとに「キャンセル」行を追加 | |||
if ( i != 0 && i % 30 == 0 ) { | |||
m.Add( "", 0, meMenuSeparator ); | |||
m.Add( " キャンセル", 0 ); | |||
m.Add( "", 0, meMenuSeparator ); | |||
} | |||
m.Add( mArray[i][0], mArray[i][1], mArray[i][2] ); | |||
} | |||
} | |||
// 配列から「空行+空白行」をポップアップメニューに追加する | // 配列から「空行+空白行」をポップアップメニューに追加する | ||
if ( re ) { | if ( re && b ) { | ||
if ( b != h ) { // ( n + w ) > h | if ( b != h ) { // ( n + w ) > h | ||
m.Add( " すべての空行+空白行: " + SeparateNum( b ) + " 行", 0 ); // , meMenuGrayed | m.Add( " すべての空行+空白行: " + SeparateNum( b ) + " 行", 0 ); // , meMenuGrayed | ||
| 235行目: | 314行目: | ||
} | } | ||
} | } | ||
if ( w && | if ( w && n + h != b ) { // ( wArray.length > 0 ) && ( n + h != b ) | ||
var sm2 = CreatePopupMenu(); | var sm2 = CreatePopupMenu(); | ||
m.AddPopup( " すべての空白行: " + SeparateNum( w ) + " 行 (&W)", sm2 ); | m.AddPopup( " すべての空白行: " + SeparateNum( w ) + " 行 (&W)", sm2 ); | ||
| 249行目: | 328行目: | ||
} | } | ||
} | } | ||
if ( ( n && st ) || ( w && | if ( ( n && st ) || ( w && n + h != b ) ) | ||
m.Add( "", 0, meMenuSeparator ); | m.Add( "", 0, meMenuSeparator ); | ||
// キャンセルを兼ねる(Space キーでキャンセル可) , meMenuGrayed | // キャンセルを兼ねる(Space キーでキャンセル可) , meMenuGrayed | ||
m.Add( " ▼ 一致した行: " + SeparateNum( h ) + " 行 ▼\t& ", 0 ); | m.Add( " ▼ 一致した行: " + SeparateNum( h ) + " 行 ▼\t& ", 0 ); | ||
for ( var i = 0; i < h; i ++ ) { // h == | for ( var i = 0; i < h; i ++ ) { // h == hArray.length | ||
// 30件ごとに「キャンセル」行を追加 | // 30件ごとに「キャンセル」行を追加 | ||
if ( i != 0 && i % 30 == 0 ) { | if ( i != 0 && i % 30 == 0 ) { | ||
| 262行目: | 341行目: | ||
m.Add( hArray[i][0], hArray[i][1], hArray[i][2] ); | m.Add( hArray[i][0], hArray[i][1], hArray[i][2] ); | ||
} | } | ||
} // end if () { 配列から「空行+空白行」をポップアップメニューに追加する } | |||
// 検索開始からポップアップメニューを表示するまでの所要時間を取得 | |||
// (Javascript 時間計測のマクロでの分解能は 16ms とのこと) | |||
if ( timerEnable ) { | |||
var elapsed = new Date().getTime() - start; | |||
var timerStatus = | |||
" [ " + ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" ) + " 秒 ]"; | |||
} | } | ||
// ポップアップメニューを表示するのは、検索ヒット行が複数のとき | // ポップアップメニューを表示するのは、検索ヒット行が複数のとき | ||
if ( | if ( hit > 1 || b > 1) { | ||
// ポップアップメニューを出すまえにステータスバー表示させること | // ポップアップメニューを出すまえにステータスバー表示させること | ||
Status = ( | Status = ( | ||
( re ? " 一致した行数: " + SeparateNum( h ) + " 行" | ( re ? " 一致した行数: " + SeparateNum( h ) + " 行" | ||
+ " / すべての空(白)行数: " + SeparateNum( b ) + " 行 / " : | |||
/*!re*/ ( gt ? ( " ヒット数: " + SeparateNum( gt ) + " 件 ・ " ) : | |||
" ヒットした行数: " | |||
) | |||
+ SeparateNum( hit ) + " 行 / " // ヒット:した行数 | |||
) | ) | ||
+ " | + "全体の行数: " + SeparateNum( lines ) // | ||
+ ( | + ( $LineColumnView ? " 行 (表示行)" : " 行 (論理行)" ) | ||
+ ( timerEnable ? timerStatus : "" ) | |||
); | ); | ||
/* カーソル位置にポップアップメニューを表示 */ | /* カーソル位置にポップアップメニューを表示 */ | ||
var y = m.Track( mePosMouse ); // Track( 0 ) ならキャレット位置 | var y = m.Track( mePosMouse ); // Track( 0 ) ならキャレット位置 | ||
/* | /* 選択した行番号(行頭)にジャンプして、検索文字列を範囲選択 */ | ||
if ( y | if ( y ) { | ||
s.SetActivePoint( | s.SetActivePoint( posMode, 1, y ); | ||
// 空白行でジャンプしたときは検索履歴に残さない | // 空白行でジャンプしたときは検索履歴に残さない | ||
if ( re && d.GetLine( y, | if ( re && d.GetLine( y, lineMode ) ) | ||
// 行(空白文字列)全体を範囲選択する(※完全な空行 ^\n では範囲選択しない) | // 行(空白文字列)全体を範囲選択する(※完全な空行 ^\n では範囲選択しない) | ||
s.SetAnchorPoint( | s.SetAnchorPoint( posMode, 1, y + 1 ); | ||
// 文字列でジャンプしたとき | // 文字列でジャンプしたとき | ||
else if ( ! re ) { | else if ( ! re ) { | ||
if ( historyDisable ) { | if ( historyDisable ) { | ||
// 検索履歴に残さない | // 検索履歴に残さない ※「検索文字列の強調表示」なし | ||
s.SetActivePos( s.GetActivePos() + findCaseTF( d.GetLine( y, | s.SetActivePos( s.GetActivePos() + findCaseTF( d.GetLine( y, lineMode ), st ) ); | ||
s.SetAnchorPos( s.GetActivePos() + st.length ); | s.SetAnchorPos( s.GetActivePos() + st.length ); | ||
} | } | ||
else { | else { | ||
// 検索履歴に残す | // 検索履歴に残す ※ Mery の検索機能で文字列を範囲選択 | ||
s.Find( st, meFindNext ); | s.Find( st, meFindNext ); | ||
d.HighlightFind = highlightEnable; // 「検索文字列の強調表示」を解除する/しない | d.HighlightFind = highlightEnable; // 「検索文字列の強調表示」を解除する/しない | ||
} | } | ||
} | } | ||
ScrollY = s.GetActivePointY( mePosView ); | ScrollY = ( ScrollY == sy ) ? ScrollY : | ||
cancel = 0; // cancel フラグを解除 | s.GetActivePointY( mePosView ); | ||
cancel = 0; // cancel フラグを解除 | |||
} | } | ||
/* キャンセルした場合 */ | /* キャンセルした場合 */ | ||
// | // ポップアップメニューをキャンセルした場合 ( y == 0 ) | ||
else cancel = 3; | else cancel = 3; | ||
} // end if { ポップアップメニューを表示 } | } // end if () { ポップアップメニューを表示 } | ||
// | |||
// ほかの行でヒットしなかったとき ( h == 0 ) | |||
else cancel = 4; | else cancel = 4; | ||
} // end else { ポップアップメニューでジャンプ先リスト } | } // end else { ポップアップメニューでジャンプ先リスト } | ||
/* | /* ジャンプしなかったときは、キャレット位置/選択範囲を復帰 */ | ||
if ( cancel ) { | if ( cancel ) { | ||
if ( | if ( pos || pos === 0 ) | ||
s.SetActivePos( | s.SetActivePos( pos ); | ||
else if ( anc < act ) | else if ( anc < act ) | ||
s.SetActivePos( act, true ); | s.SetActivePos( act, true ); | ||
| 324行目: | 419行目: | ||
s.SetActivePos( act, true ); | s.SetActivePos( act, true ); | ||
} | } | ||
// | ScrollX = sx; ScrollY = sy; | ||
// キャンセルフラグの値が 1 or 2 のとき、所要時間の計測終了 | |||
if ( timerEnable && ! elapsed ) { | |||
var elapsed = new Date().getTime() - start; | |||
var timerStatus = | |||
" [ " + ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" ) + " 秒 ]"; | |||
} | |||
// ステータスバーにキャンセルメッセージを表示 | |||
Status = ( | Status = ( | ||
( ( cancel == 1 ) ? " 検索文字列がありません(空行)。" : | ( ( cancel == 1 ) ? " 検索文字列がありません(空行)。 " : | ||
( cancel == 2 ) ? " 検索文字列に【 改行 】を含めることはできません。" : | ( cancel == 2 ) ? " 検索文字列に【 改行 】を含めることはできません。 " : | ||
( cancel == 3 ) ? " | ( cancel == 3 ) ? " ヒット数: " // 検索ジャンプをキャンセルしました。 | ||
+ ( gt ? ( SeparateNum( gt ) + " 件 ・ " ) : "" ) | + ( gt ? ( SeparateNum( gt ) + " 件 ・ " ) : " " ) | ||
+ SeparateNum( h ) + " 行" : | + SeparateNum( h ) + " 行 / " : | ||
( cancel == 4 ) ? " | ( cancel == 4 ) ? " ヒットなし。 " : // ほかの行には見つかりませんでした。 | ||
/* else */ " 無効な検索文字列。" // ← 使われないはず | /* else */ " 無効な検索文字列。 " // ← 使われないはず | ||
) | ) | ||
+ " | + "全体の行数: " + SeparateNum( lines ) | ||
+ ( | + ( $LineColumnView ? " 行 (表示行)" : " 行 (論理行)" ) | ||
+ ( timerEnable ? timerStatus : "" ) | |||
); | ); | ||
} | } | ||
/* 関数 findCaseTF( str, st ) */ | /* 関数 findCaseTF( str, st ) */ | ||
// 文字列 str 内で st を検索するさいに「大文字/小文字を区別」する/しない | // 文字列 str 内で st を検索するさいに「大文字/小文字を区別」する/しない | ||
// ヒットすればヒットした位置( 0 ~ )、ヒットしなければ -1 を返す | |||
function findCaseTF( str, st ) { | function findCaseTF( str, st ) { | ||
return caseEnable ? str.indexOf( st ) : | return caseEnable ? str.indexOf( st ) : | ||
/* else */ str.toLowerCase().indexOf( st.toLowerCase() ) | /* else */ str.toLowerCase().indexOf( st.toLowerCase() ) | ||
} | } | ||
/* 関数 Marking() */ | /* 関数 Marking() */ | ||
// ポップアップメニューの右側に表示するマーキング | // ポップアップメニューの右側に表示するマーキング | ||
function Marking() { | function Marking() { | ||
var _check = ( | var _check = ( | ||
// 変数の宣言の行: "var st" ... / "var hoge = piyo , st" ... | |||
a[i].match( RegExp( "\\b(?:var |let |const )(?:\\s*|[^\(]+[,]\\s+)[$]?" | |||
+ stQuote + "(?=\\s*(?:[=,;]|$))" , "" ) ) ? | |||
"\t ← v a r" : // ) ← ※カッコの数のツジツマあわせ | |||
// 変数の宣言の行: "var hoge = fuga(), st " ... | |||
( a[i].match( RegExp( "\\b(?:var |let |const ).*?\\(.*?[,]\\s*[$]?" | |||
+ stQuote + "(?=\\s*(?:[=,;]|$))" , "" ) ) | |||
&& SearchCloseBrc( a[i], stQuote ) ) ? // 閉じていないカッコがあるかの簡易的なチェック | |||
"\t ← v a r" : // ) ← ※同上 | |||
// 変数に値を代入している行: "st = fuga" | |||
a[i].match( RegExp( "\\b" + stQuote + "(?=\\s*=(?!=))" , "" ) ) ? | |||
"\t ← s u b" : | |||
// 関数の定義の行 | |||
a[i].match( RegExp( "\\bfunction +[$]?" + stQuote + "(?=[\\s(])" , "" ) ) ? | |||
"\t ← f n" : // ) ← ※同上 | |||
( i != ty && a[i] == activeLine ) ? "\t **" : // ①アクティブ行と完全一致する行(重複行) | ( i != ty && a[i] == activeLine ) ? "\t **" : // ①アクティブ行と完全一致する行(重複行) | ||
( t && t.length > 1 ) ? "\t x" + t.length : // ②検索文字列が複数ヒットした行 | ( t && t.length > 1 ) ? "\t x" + t.length : // ②検索文字列が複数ヒットした行 | ||
| 357行目: | 482行目: | ||
( i != ty && a[i] == st ) ? "\t *" : // ④検索文字列と完全一致する行 | ( i != ty && a[i] == st ) ? "\t *" : // ④検索文字列と完全一致する行 | ||
"" // ⑤検索文字列を含む行 | "" // ⑤検索文字列を含む行 | ||
); | ) ; | ||
return _check; | return _check; | ||
} | } | ||
/* 関数 Labeling( str, num ) */ | /* 関数 Labeling( str, num ) */ | ||
// ポップアップメニューに表示する文字列の整形 | // ポップアップメニューに表示する文字列の整形 | ||
function Labeling( line, i ) { | function Labeling( line, i ) { // Labeling( a[i], i ) ※ line = a[i] ヒットした行全体 | ||
// 行頭空白を除去、空白文字は半角スペースに置換、文字数を圧縮して取得 | // 行頭空白を除去、空白文字は半角スペースに置換、文字数を圧縮して取得 | ||
// | // 判別しづらい半角メタ文字を全角に置きかえる | ||
var label = line.replace( /^[\t ]+/ , "" ) | var label = line.replace( /^[\t ]+/ , "" ) | ||
.replace( /\{ | .replace( /(\t|[ ]{2,}|[ ])+/g , " " ) | ||
.replace( / | .replace( /[.,:;(){}]/g , | ||
function( $0 ) { return String.fromCharCode( $0.charCodeAt( 0 ) + 0xFEE0 ) } | |||
); | |||
label = ( | label = ( | ||
( ! line.length ) ? "( 空行 )" : | ( ! line.length ) ? "( 空行 )" : | ||
| 378行目: | 506行目: | ||
/* else */ label | /* else */ label | ||
); | ); | ||
return ( " " + i ).slice( -4 ) + " : " + label; | return ( " " + i ).slice( -4 ) + " : " + label; | ||
} | } | ||
/* 関数 SeparateNum( num ) */ | /* 関数 SeparateNum( num ) */ | ||
// 数値を3ケタ区切りに | // 数値を3ケタ区切りに | ||
function SeparateNum( num ) { | function SeparateNum( num ) { | ||
if ( ! num ) { num = ""; } | |||
return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g , "$1," ); | return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g , "$1," ); | ||
} | |||
/* 関数 SearchCloseBrc( str, word ) */ | |||
// 閉じていないカッコがないかを簡易的にチェックする(閉じていなければ false ) | |||
function SearchCloseBrc( str, word ) { | |||
var txt = str.substr( str.search( /\b(?:var |let |const )/ ), str.search( RegExp( "\\b" + word + "\\b" , "" ) ) ); | |||
var oBrc = txt.match( /\(/g ); // 開きカッコの数 | |||
var cBrc = txt.match (/\)/g ); // 閉じカッコの数 | |||
return ( ! cBrc || oBrc.length > cBrc.length ) ? 0 : 1; | |||
} | } | ||
</source> | </source> | ||
[[ポップアップメニューで検索先にジャンプ#人柱版のソースコード|>> もとのページ]] | [[ポップアップメニューで検索先にジャンプ#人柱版のソースコード|>> もとのページ]] | ||
2018年12月13日 (木) 20:53時点における版
ポップアップメニューで検索先にジャンプ(sukemaru 版)
人柱版
「表示行」で運用した場合の 動作検証が不十分 ですが、以下の追加オプションにご興味のある方は ZIP 書庫 内の「人柱版(空行+空白行検索に対応)」フォルダの JS ファイルをお使いください。
動作に異常があるようでしたら、ソースコード内の設定セクションで「人柱版の設定項目」を無効化( false )してください。
▼ 追加オプション ▼
- 「検索処理の所要時間」をステータスバーに表示します(◆変数で設定)。
- 人柱版では処理が遅くなる追加機能が多いので…。
- 「行の表示方法」の設定を Mery.ini から自動取得するかしないかを選択できます(◆変数で設定)。
- ただし、ini ファイルが肥大化またはフラグメントしていると、処理が多少遅くなります。
- 検索文字列を検索/置換ダイアログの「検索履歴に残すか残さないか」を選択できます(◆変数で設定)。
- 「残さない」場合は Mery の検索機能を使用せずにジャンプするため、通常版と共通の設定項目「検索文字列の強調表示を残す」も無効になります。
- 検索のさいに「大文字/小文字を区別」するかしないかを選択できます(◆変数で設定)。
- 空行にキャレットがある状態か、"末尾改行をふくめて" 空白行を範囲選択している状態から、「すべての空行+空白行」を検索できるオプションを追加しました(変数で設定)。
- 「空行+空白行」オプションが有効 ( true ) の場合は、末尾改行 "\n" をふくめて「空白文字のみの行」を範囲選択しているときに、すべての「空行+空白行」を検索対象にします。末尾改行をふくめずに「空白文字のみの行」を範囲選択しているときは「一致する空白文字列」を検索対象にします。
- 「空行+空白行」オプションが無効 ( false ) の場合、空白文字のみの行」を範囲選択しているときには「一致する空白文字列」を検索対象にします。空行で実行した場合にはポップアップメニューは表示されません。
- ※「空行+空白行」が対象のとき以外は正規表現を使わずに行単位で検索するので、選択範囲が複数行(末尾以外に改行 "\n" がある)の場合や、空白行オプションが無効で選択範囲が空行 "^\n" の場合は検索できません。
- 検索対象が「空行+空白行」でないときは、ヒットした行数とは別に「ヒットした件数」をステータスバーに表示できます(◆変数で設定)。「ヒット件数」の判定は、大文字/小文字オプションの設定に依拠します。
- 検索対象が「空行+空白行」でないとき、ポップアップメニューの右隅に以下のマーキングを表示できます(「ヒット件数」オプションが有効の場合のみ)。
- JavaScript で検索文字列が変数/関数名のとき、定義行に「 ← var 」「 ← fn 」マーク
- 検索文字列が行全体のとき、アクティブ行に「 ⏎ 」マーク
- アクティブ行と完全に一致する重複行に「 ** 」マーク (※行検索でないときにも表示)
- 検索文字列と完全に一致する行に「 * 」マーク
- 検索文字列が複数回ヒットした行に「 x2 」マーク
- ※「一致」の判定では、つねに大文字/小文字を区別します。
- ポップアップメニューを Space キーでもキャンセルできるようにしました。ただし、メニューに表示されるヒットした行の文字列に「アンパサンドと半角スペース "&␣"」があるときは Esc キーのみ( "&&␣" なら可)。
※大きな文書の場合、「空行/空白行/空白文字列」や「頻出する文字/単語」の検索では処理に時間がかかります。
※「人柱版 設定項目」の変数の値をすべて無効 false にすれば通常版とほぼおなじ動作になります。
ソースコード
#title = "ジャンプ"
#tooltip = "ポップアップメニューで検索先にジャンプ"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",229
// ◆ 人柱版 ◆ 「大文字/小文字の区別」に対応
// 「空行+空白行」の検索に対応
// 「ヒット件数(出現回数)」を表示
// スペースキーでポップアップメニューをキャンセル可
// 「検索履歴に残さない」を追加(■通常版へ逆移植済み)
// 「行の表示方法」を Mery.ini から取得
// 「自動マーカー」オプションを廃止(デフォルト: 自動マーカー有効)
// 「検索所要時間」の表示(■通常版へ逆移植済み)
// 検索ジャンプ後のスクロールの挙動を調整(■通常版へ逆移植済み)
// 「変数/関数の定義行」のマーキング
/**
* ------------------------------------------------------------
* "ポップアップメニューで検索先にジャンプ"
* pooupJump.js
* Original Copyright: 手石 (2014/04/04)
* ------------------------------------------------------------
* Modified by: sukemaru (2018/11/12 - 2018/12/13)
* ------------------------------------------------------------
*/
var start = new Date().getTime(); // 所要時間の計測開始
// ---------- ▼ 通常版 設定項目 ▼ ----------
// ■行の表示方法 (true; 論理座標 /false; 表示座標)
// ※ ◆人柱版◆ の追加設定で autoLineModeEnable = true の場合は無効(自動設定)
var logical = true; // ■初期値 = true; (論理座標)
// ■検索文字列の強調表示を残すか? (true; 残す /false; 残さない)
// ※ ◆人柱版◆ の追加設定で historyDisable = true の場合は無効(強調表示しない)
var highlightEnable = false; // ■初期値 = true; (残す)
// ---------- ▼ 人柱版 設定項目 ▼ ----------
// ◆人柱版のオプションを有効にすると処理が遅くなります
// ◆検索処理の所要時間を表示するか? (true; する /false; しない)
var timerEnable = true; // ◆初期値 = true; (する)
// ◆行の表示方法を Mery.ini から自動で読み込むか? (true; 読み込む /false; 読み込まない)
// ※ ini ファイルが肥大化またはフラグメントしていると処理が遅くなる
var autoLineModeEnable = true; // ◆初期値 = false; (読み込まない)
// ◆検索文字列を「検索履歴」に残さない? (true; 残さない / false; 残す)
// ※ historyDisable = true の場合、通常版の設定 highliteEnable は無効になる(強調表示しない)
var historyDisable = true; // ◆初期値 = true; (残さない)
// ◆検索文字列の「大文字/小文字」を区別するか? (true; 区別する / false; 区別しない)
var caseEnable = true; // ◆初期値 = true; (区別する)
// ◆空行/空白行を検索対象にするか? (true; する /false; しない)
var blankEnable = true; // ◆初期値 = true; (する)
// ◆ヒット件数(出現回数)を表示するか? (true; する /false; しない)
var countEnable = true; // ◆初期値 = true; (する)
// ---------- ▼ 手石版 設定項目 ▼ ----------
// ●ポップアップメニューに表示する文字数
var menuWidth = 66;
// ---------- ▲ 設定項目 ここまで ▲ ----------
/* ■ポップアップメニューの「行番号の表示方法」 */
var $LineColumnView = logical ? 0 : 1;
// Mery.ini から「行の表示方法」を取得する
if (autoLineModeEnable ) {
var WshShell = new ActiveXObject( "WScript.Shell" );
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
// ini を探す(Zip版なら Mery.exe のフォルダ、インストーラ版なら %appdata%\Mery フォルダ)
var portableIni = editor.FullName.slice( 0, 0 - "mery.exe".length ) + "Mery.ini";
var iniPath = Fso.FileExists( portableIni ) ? portableIni :
WshShell.ExpandEnvironmentStrings( "%APPDATA%\\Mery\\Mery.ini" );
var iniFile = Fso.OpenTextFile( iniPath, 1 );
var iniText = iniFile.ReadAll();
$LineColumnView = Number( iniText.match( /^LineColumnView=[01]$/m ).shift().slice( -1 ) );
iniFile.Close();
}
// ini から取得した設定値にもとづいて変数に
var posMode = $LineColumnView ? mePosView : mePosLogical;
var lineMode = $LineColumnView ? meGetLineView : 0;
var d = document, s = document.selection;
var sx = ScrollX, sy = ScrollY;
// 選択範囲の先頭位置(行番号)と、文書全体の行数(論理行/表示行)
var ty = s.GetTopPointY( posMode );
var lines = d.GetLines( lineMode );
/* 検索文字列の準備 */
var blank = new RegExp( "^[\t ]*$" , "" ); // 空白行の正規表現
var re; // "空白行の正規表現検索" フラグ
// 選択範囲なしならキャレット位置の単語を選択する
if ( s.IsEmpty ) {
var p = s.GetActivePos(); // "選択範囲なし" のフラグ
s.SelectWord();
}
var st = s.Text; // 検索文字列
// 選択範囲の末尾が改行 "\n" なら検索文字列から除外する
if ( ! st || st.charAt( st.length - 1 ) == "\n" ) {
st = st.replace( /\n$/g , "" );
// 自動マーカーを効かせるために選択範囲も調整する
var anc = s.GetAnchorPos();
var act = s.GetActivePos(); // "末尾調整" フラグ
if ( anc < act && ! ( blankEnable && st.match( blank ) ) )
s.SetActivePos( act - 1, true );
if ( act < anc && ! ( blankEnable && st.match( blank ) ) ) {
s.SetAnchorPos( anc - 1 );
s.SetActivePos( act, true );
}
if ( blankEnable && st.match( blank ) )
re = true; // "空白行の正規表現検索" フラグ
}
// 文書末尾の空白行の場合でも "空白行の正規表現検索" フラグ
else if ( blankEnable && st.match( blank ) && st == d.GetLine( ty, lineMode ) )
re = true;
var cancel = 5; // "キャンセル" フラグ
// 検索文字列がないとき(空行)
if ( ! blankEnable && ! st )
cancel = 1;
// 検索条件エラー(選択範囲に改行あり)
else if ( st.match( /\n/g ) )
cancel = 2;
// ポップアップメニューでジャンプ先リスト
else {
/* 文書全体を行単位で分割し、配列に */
for( var a = [ "" ], i = 1; i <= lines ; i ++ ) // a[0] = "" / i = 行番号
a.push( d.GetLine( i, lineMode ) );
/* ポップアップメニューの準備 */
var m = CreatePopupMenu();
// 「文字列」の検索では先頭に「キャンセル」のアイテムを表示
if ( ! re ) {
m.Add( " キャンセル & ", 0 ); // Space キーでキャンセル可
m.Add( "", 0, meMenuSeparator );
// Grand total, Hit, Variables
var mArray = [], t, gt = 0, hit = 0, v = 0, check = "", flags;
// アクティブ行(検索開始行)全体の文字列を取得
if ( countEnable )
var activeLine = d.GetLine( ty, lineMode );
}
// 「空行+空白行」の検索ではパターンごとの配列を使用する
else {
var hArray = [], nArray = [], wArray = [];
// Hit ( match completely ), Blank line ( n + w ), New line ( ^$ ), White space ( ^[\s ]+$ )
var h = 0, b = 0, n = 0, w = 0;
}
/* 検索文字列がヒットした行をポップアップメニューのアイテムとして取得する */
var stQuote = st.replace( /\W/g , "\\$&" );
var reg = new RegExp( stQuote , caseEnable ? "g" : "gi" );
for( var i = 1; i < a.length; i ++ ) { // a[0] = 空要素、i = 行番号 => y
// 空行からの検索なら「空行+空白行」以外はスキップ
if ( re && ! a[i].match( blank ) )
continue;
// 「検索文字列」がヒットしたら
if ( ( ! re && findCaseTF( a[i], st ) >= 0 ) || ( re && a[i].match( blank ) ) ) {
// 行内でのヒット回数
if ( ! re && countEnable ) {
t = a[i].match( reg );
gt += t.length; // 総ヒット回数(大文字/小文字を区別できる)
check = Marking(); // 右側につけるマーキング
}
// アクティブ行は左に ✓ チェックマーク付き
flags = ( i == ty ) ? meMenuChecked : 0; // + meMenuGrayed
/* ポップアップメニューにアイテム(行)を追加する */
// 「文字列」の検索では、行頭空白を除去、空白文字を半角スペースに置換、文字数を圧縮
if ( ! re ) {
// 変数/関数の定義行はメニューの先頭にも置く
if ( countEnable && check.match( /←/ ) ) {
m.Add( Labeling( a[i], i ) + check, i, flags );
v ++;
}
// 「検索文字列がヒットした行」を配列に格納
mArray.push( [ Labeling( a[i], i ) + check, i, flags ] ); // ヒットした行
hit ++; // ヒットした行数
}
// 「空行+空白行」の検索ではサブメニュー用の配列に分別
else { // if ( re )
b ++; // 空行+空白行の総数
if ( a[i] == st ) {
hArray.push( [ Labeling( a[i], i ), i, flags ] ); // 一致した行
h ++; // 一致した行数
}
if ( st && ! a[i] ) {
nArray.push( [ Labeling( a[i], i ), i, flags ] ); // 空行
n ++; // 空行数
}
else if ( a[i] ) {
wArray.push( [ Labeling( a[i], i ), i, flags ] ); // 空白行
w ++; // 空白行数
}
}
} // end if () { 検索文字列がヒットしたら }
} // end for () { ヒットした行を取得する }
// 配列から「検索文字列がヒットした行」をポップアップメニューに追加する
if ( ! re && hit ) {
if ( v )
m.Add( "", 0, meMenuSeparator );
for ( var i = 0; i < hit; i ++ ) {
// 30件ごとに「キャンセル」行を追加
if ( i != 0 && i % 30 == 0 ) {
m.Add( "", 0, meMenuSeparator );
m.Add( " キャンセル", 0 );
m.Add( "", 0, meMenuSeparator );
}
m.Add( mArray[i][0], mArray[i][1], mArray[i][2] );
}
}
// 配列から「空行+空白行」をポップアップメニューに追加する
if ( re && b ) {
if ( b != h ) { // ( n + w ) > h
m.Add( " すべての空行+空白行: " + SeparateNum( b ) + " 行", 0 ); // , meMenuGrayed
m.Add( "", 0, meMenuSeparator );
}
if ( n && st ) { // ( nArray.length > 0 ) && ( st.length > 0 )
var sm1 = CreatePopupMenu();
m.AddPopup( " すべての空行: " + SeparateNum( n ) + " 行 (&N)", sm1 );
for ( var i = 0; i < n; i ++ ) {
// 30件ごとに「キャンセル」行を追加
if ( i % 30 == 0 ) {
if ( i != 0 )
sm1.Add( "", 0, meMenuSeparator );
sm1.Add( " キャンセル", 0 );
sm1.Add( "", 0, meMenuSeparator );
}
sm1.Add( nArray[i][0], nArray[i][1], nArray[i][2] );
}
}
if ( w && n + h != b ) { // ( wArray.length > 0 ) && ( n + h != b )
var sm2 = CreatePopupMenu();
m.AddPopup( " すべての空白行: " + SeparateNum( w ) + " 行 (&W)", sm2 );
for ( var i = 0; i < w; i ++ ) {
// 30件ごとに「キャンセル」行を追加
if ( i % 30 == 0 ) {
if ( i != 0 )
sm2.Add( "", 0, meMenuSeparator );
sm2.Add( " キャンセル", 0 );
sm2.Add( "", 0, meMenuSeparator );
}
sm2.Add( wArray[i][0], wArray[i][1], wArray[i][2] );
}
}
if ( ( n && st ) || ( w && n + h != b ) )
m.Add( "", 0, meMenuSeparator );
// キャンセルを兼ねる(Space キーでキャンセル可) , meMenuGrayed
m.Add( " ▼ 一致した行: " + SeparateNum( h ) + " 行 ▼\t& ", 0 );
for ( var i = 0; i < h; i ++ ) { // h == hArray.length
// 30件ごとに「キャンセル」行を追加
if ( i != 0 && i % 30 == 0 ) {
m.Add( "", 0, meMenuSeparator );
m.Add( " キャンセル", 0 );
m.Add( "", 0, meMenuSeparator );
}
m.Add( hArray[i][0], hArray[i][1], hArray[i][2] );
}
} // end if () { 配列から「空行+空白行」をポップアップメニューに追加する }
// 検索開始からポップアップメニューを表示するまでの所要時間を取得
// (Javascript 時間計測のマクロでの分解能は 16ms とのこと)
if ( timerEnable ) {
var elapsed = new Date().getTime() - start;
var timerStatus =
" [ " + ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1 $2" ) + " 秒 ]";
}
// ポップアップメニューを表示するのは、検索ヒット行が複数のとき
if ( hit > 1 || b > 1) {
// ポップアップメニューを出すまえにステータスバー表示させること
Status = (
( re ? " 一致した行数: " + SeparateNum( h ) + " 行"
+ " / すべての空(白)行数: " + SeparateNum( b ) + " 行 / " :
/*!re*/ ( gt ? ( " ヒット数: " + SeparateNum( gt ) + " 件 ・ " ) :
" ヒットした行数: "
)
+ SeparateNum( hit ) + " 行 / " // ヒット:した行数
)
+ "全体の行数: " + SeparateNum( lines ) //
+ ( $LineColumnView ? " 行 (表示行)" : " 行 (論理行)" )
+ ( timerEnable ? timerStatus : "" )
);
/* カーソル位置にポップアップメニューを表示 */
var y = m.Track( mePosMouse ); // Track( 0 ) ならキャレット位置
/* 選択した行番号(行頭)にジャンプして、検索文字列を範囲選択 */
if ( y ) {
s.SetActivePoint( posMode, 1, y );
// 空白行でジャンプしたときは検索履歴に残さない
if ( re && d.GetLine( y, lineMode ) )
// 行(空白文字列)全体を範囲選択する(※完全な空行 ^\n では範囲選択しない)
s.SetAnchorPoint( posMode, 1, y + 1 );
// 文字列でジャンプしたとき
else if ( ! re ) {
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; // 「検索文字列の強調表示」を解除する/しない
}
}
ScrollY = ( ScrollY == sy ) ? ScrollY :
s.GetActivePointY( mePosView );
cancel = 0; // cancel フラグを解除
}
/* キャンセルした場合 */
// ポップアップメニューをキャンセルした場合 ( y == 0 )
else cancel = 3;
} // end if () { ポップアップメニューを表示 }
// ほかの行でヒットしなかったとき ( h == 0 )
else cancel = 4;
} // end else { ポップアップメニューでジャンプ先リスト }
/* ジャンプしなかったときは、キャレット位置/選択範囲を復帰 */
if ( cancel ) {
if ( pos || pos === 0 )
s.SetActivePos( pos );
else if ( anc < act )
s.SetActivePos( act, true );
else if ( act < anc ) {
s.SetAnchorPos( anc );
s.SetActivePos( act, true );
}
ScrollX = sx; ScrollY = sy;
// キャンセルフラグの値が 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 ) ? " ヒット数: " // 検索ジャンプをキャンセルしました。
+ ( gt ? ( SeparateNum( gt ) + " 件 ・ " ) : " " )
+ SeparateNum( h ) + " 行 / " :
( cancel == 4 ) ? " ヒットなし。 " : // ほかの行には見つかりませんでした。
/* else */ " 無効な検索文字列。 " // ← 使われないはず
)
+ "全体の行数: " + SeparateNum( lines )
+ ( $LineColumnView ? " 行 (表示行)" : " 行 (論理行)" )
+ ( timerEnable ? timerStatus : "" )
);
}
/* 関数 findCaseTF( str, st ) */
// 文字列 str 内で st を検索するさいに「大文字/小文字を区別」する/しない
// ヒットすればヒットした位置( 0 ~ )、ヒットしなければ -1 を返す
function findCaseTF( str, st ) {
return caseEnable ? str.indexOf( st ) :
/* else */ str.toLowerCase().indexOf( st.toLowerCase() )
}
/* 関数 Marking() */
// ポップアップメニューの右側に表示するマーキング
function Marking() {
var _check = (
// 変数の宣言の行: "var st" ... / "var hoge = piyo , st" ...
a[i].match( RegExp( "\\b(?:var |let |const )(?:\\s*|[^\(]+[,]\\s+)[$]?"
+ stQuote + "(?=\\s*(?:[=,;]|$))" , "" ) ) ?
"\t ← v a r" : // ) ← ※カッコの数のツジツマあわせ
// 変数の宣言の行: "var hoge = fuga(), st " ...
( a[i].match( RegExp( "\\b(?:var |let |const ).*?\\(.*?[,]\\s*[$]?"
+ stQuote + "(?=\\s*(?:[=,;]|$))" , "" ) )
&& SearchCloseBrc( a[i], stQuote ) ) ? // 閉じていないカッコがあるかの簡易的なチェック
"\t ← v a r" : // ) ← ※同上
// 変数に値を代入している行: "st = fuga"
a[i].match( RegExp( "\\b" + stQuote + "(?=\\s*=(?!=))" , "" ) ) ?
"\t ← s u b" :
// 関数の定義の行
a[i].match( RegExp( "\\bfunction +[$]?" + stQuote + "(?=[\\s(])" , "" ) ) ?
"\t ← f n" : // ) ← ※同上
( i != ty && a[i] == activeLine ) ? "\t **" : // ①アクティブ行と完全一致する行(重複行)
( t && t.length > 1 ) ? "\t x" + t.length : // ②検索文字列が複数ヒットした行
( i == ty && a[i] == st ) ? "\t ⏎" : // ③アクティブ行(行検索のとき)✓↵
( i != ty && a[i] == st ) ? "\t *" : // ④検索文字列と完全一致する行
"" // ⑤検索文字列を含む行
) ;
return _check;
}
/* 関数 Labeling( str, num ) */
// ポップアップメニューに表示する文字列の整形
function Labeling( line, i ) { // Labeling( a[i], i ) ※ line = a[i] ヒットした行全体
// 行頭空白を除去、空白文字は半角スペースに置換、文字数を圧縮して取得
// 判別しづらい半角メタ文字を全角に置きかえる
var label = line.replace( /^[\t ]+/ , "" )
.replace( /(\t|[ ]{2,}|[ ])+/g , " " )
.replace( /[.,:;(){}]/g ,
function( $0 ) { return String.fromCharCode( $0.charCodeAt( 0 ) + 0xFEE0 ) }
);
label = (
( ! line.length ) ? "( 空行 )" :
( ! label.length ) ?
( line == st ) ? "( 空白行 " + line.length + " 文字 * )" :
"( 空白行 " + line.length + " 文字 )" :
( label.length > menuWidth + 1 ) ? label.slice( 0, menuWidth ) + "..." :
/* else */ label
);
return ( " " + i ).slice( -4 ) + " : " + label;
}
/* 関数 SeparateNum( num ) */
// 数値を3ケタ区切りに
function SeparateNum( num ) {
if ( ! num ) { num = ""; }
return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g , "$1," );
}
/* 関数 SearchCloseBrc( str, word ) */
// 閉じていないカッコがないかを簡易的にチェックする(閉じていなければ false )
function SearchCloseBrc( str, word ) {
var txt = str.substr( str.search( /\b(?:var |let |const )/ ), str.search( RegExp( "\\b" + word + "\\b" , "" ) ) );
var oBrc = txt.match( /\(/g ); // 開きカッコの数
var cBrc = txt.match (/\)/g ); // 閉じカッコの数
return ( ! cBrc || oBrc.length > cBrc.length ) ? 0 : 1;
}
スポンサーリンク