HTML・CSS系の未記入箇所へ移動する マクロ

`<TAG attr="|">|</TAG>`や`css-prop:|;`のような未記入っぽい箇所[^1]へカーソルを移動させるマクロです。

Emmet や Zen-Coding で展開後の入力サポート用です。

[^1]: | はカーソル位置を示してます

<details><summary>**マクロコード**</summary><div>
**下検索用**

~~~~javascript:entrySearch.js
/** 未記入箇所へ移動:マクロ *******************************
HTML・CSS系ファイル内の
  <TAG attr="|">|</TAG>    css-prop: |;
のような未記入箇所へカーソルを移動するマクロ。

上下セットで使用前提＆使えるファイル種も限られるので、
段落/移動履歴/関数マーク等の移動系と兼用してキー割り当ての節約。
**********************************************************/

//-- 動作オプション ---------------------------------------
//検索方向 [N>0:下検索  N<0:上検索]
var MOVE_STEP = 1;

//先頭(末尾)から再検索
var LOOP_SEARCH = 0;

//空白のみの行(≠空行)も未記入箇所と見なす
var SPACE_ROW = 0;
//「.,)]」手前の空欄も未記入と見なす
var EMPTY_SEPARATE = 0;

//「見つかりませんでした。」
var NOT_FOUND = 'Entry-point not found.';

//拡張子orタイプ指定 (この拡張子と同タイプの拡張子 || この拡張子用のタイプ適用中)なら有効
var TYPES = ['html', 'css'];

//↑の指定等で無効な場合の代替動作
var DEF_FUNC = function(){
	return MOVE_STEP<0?GoPrevParagraph():GoNextParagraph();//次(前)の段落へ～
};


//function put(msg){if(typeof(outp)=='undefined'){TraceOut('\r\n▼-- $t @['+ExpandParameter('$M').replace(/^.*?([^\\\/]+)$/m,'$1')+'] > $f --',1),outp=1} TraceOut((''+msg).replace(/^([\S])/gm,'\t$1'),0)}

//== メイン処理 ===========================================
function entrySearch(){
	var txt=GetCookie('document','_EnTrySeArCh_ArG')||'';//外部から呼び出し用の仕込み
	if(txt){MOVE_STEP=txt-0; DeleteCookie('document','_EnTrySeArCh_ArG')}

	if(typeof(TYPES)!=='undefined' && (TYPES instanceof Array) && TYPES.length){//拡張子&タイプ判定
		var ext=ExpandParameter('$b');
		for(var i=0; i<TYPES.length; i++){if(IsSameTypeExt(TYPES[i],ext) || IsCurTypeExt(TYPES[i])){ext='ok!?'}}
		if(ext!=='ok!?'){return null}
	}

	var ms=MOVE_STEP, mm=ms<0?-1:ms>0?1:0; if(!mm){return null}
	var cx=ExpandParameter('$x')-0, cy=ny=ExpandParameter('$y')-1, ly=GetLineCount(0);
	var re=[                                                            //探索用の正規表現
			/^((.*?\<[ \t]*(\w+)\b[^\>]*?\>)\<\/[ \t]*\3\b[^\>]*?\>)(.*)$/im, //  <TAG>|</TAG>
			/^((.*?([\"\']))\3)(.*)$/im,                                      //  attr="|"
			/^((.*?(\w+)[ \t]*\:[ \t]*)[\,\;\}])(.*)$/im                      //  prop: |;
		],
		re_e=[                                                            //区切り空欄
			/^(((.*?[\,\.\(\[])[ \t]*))([\.\,\)\]].*)$/im,                    // , |,
			/^((.*?([\'\"])[ \t]*)[\,\.])(.*)$/im,                            // " |,
			/^((.*?([\,\.])[ \t]*)[\'\"])(.*)$/im                             // , |"
		],
		re_s=/^([ \t]+)$/m;                                               //空白のみの行

	while(cx || cy!=ny){//1行ずつ該当箇所を洗い出し
		var c=[]; txt=GetLineStr(cy+1).replace(/\\./g,'\\\x02'); // "\"" みたいな表記を避けとく
		for(var i=0,px,t; i<re.length; i++){px=0; t=txt; while(t.match(re[i])){t=RegExp.$4; c.push(px+RegExp.$2.length); px+=RegExp.$1.length}}
		for(var i=0,px,t; i<re_e.length && EMPTY_SEPARATE; i++){t=txt; px=0; while(t.match(re_e[i])){t=RegExp.$4; c.push(px+RegExp.$2.length); px+=RegExp.$1.length}}
		if(SPACE_ROW && txt.match(re_s)){c.push(RegExp.$1.length)}

		c.sort(function(a,b){return a<b?-1:1}); //只のsort()じゃ文字列比較;;
		if(cx--){if(mm<0){while(c[c.length-1]>=cx){c.pop()}}else{while(c[0]<=cx){c.shift()}}}//開始行では余分なの除去

		while(ms && c.length){ms-=mm; cx=mm<0?c.pop():c.shift()}//MOVE_STEP番目の該当箇所探し
		if(!ms){break}//見つかったら抜ける

		cx^=cx; cy+=mm;//次(前)の行へ
		if(cy<0 || cy>=ly){if(LOOP_SEARCH){cy=(cy+ly)%ly}else{break}}
	}
	if(!ms){//表示位置調整のため一旦行頭移動してから該当箇所へ
		SetDrawSwitch(0); MoveCursor(cy+1,1,0); MoveCursor(cy+1,cx+1,0);
		SetDrawSwitch(1); ReDraw(); return true;
	}
	StatusMsg(NOT_FOUND,0); return false;
}

if(Editor){if(entrySearch()===null){DEF_FUNC()}}
~~~~

**上検索用**

~~~~javascript:entrySearch_alt.js
/** 未記入箇所へ移動:マクロ(逆方向用) ********************/
function entrySearch_alt(){
	SetCookie('document','_EnTrySeArCh_ArG',-1);
	return ExecExternalMacro(ExpandParameter('$M').replace(/^(.*?)[^\\\/]+$/m,'$1')+'entrySearch.js');
}

if(Editor){entrySearch_alt()}
~~~~

> 丸ごとコピペで `MOVE_STEP = -1` だけ書き換えでも良いのですが、ドキュメントクッキー経由で引数付き実行みたいな事してます。
</div></details>

- 用途上、下方向&上方向用セットでの使用が前提です。
- コードの始めの方に **動作オプション** まとめてるので、適宜改変してご使用下さい。
  - デフォルトだとHTML・CSS系のファイル、又はそれら用のタイプ設定を適用時のみ動作します。
  - 上記以外の場合は、次(前)の段落へ移動 します。
- 先頭(末尾)から再検索時、一周回って同じ行にある箇所は見つけられません。

> <time datetime="2020-06-23">*06/23: 修正*</time>
行内の該当箇所の`sort()`処理の不具合修正
`,.`区切りや`[]``()`括りの空欄も検出可能に