web404

HTMLタグを状況に応じて削除するマクロ

カーソル位置と選択状況をもとに、HTMLタグを削除します。
基本的に、カーソルを含むHTML要素の開始タグと終了タグを削除します。
範囲選択していれば、選択範囲内のタグをすべて削除します。

範囲選択による削除は、タグ全体が選択範囲に含まれている必要があります。
コメントやPHPのタグも、タグとみなします。
BOX選択にも対応しています。
ただし、複数選択には非対応です。

範囲選択の有無による2つの削除機能は、完全に別物です。
タグを単独で削除したい場合は、範囲選択してもいいですが、HTMLタグを選択するマクロを使って削除したほうが早いです。

ダウンロード

delete_tag.zip

ソースコード

$ve = "area|base|br|col|embed|hr|img|input|keygen|link|param|source|track|meta|wbr";	//空要素

setcompatiblemode 0x20200;
disabledraw;
begingroupundo;

call DeleteSelected;
goto DeletePair;

DeleteSelected:	//選択範囲内のタグを削除
	if (!selecting) return;
	##xt = seltopx; ##yt = seltopy; ##xe = selendx; ##ye = selendy;
	##rect = 0;
	if (rectselecting) ##rect = 1;
	##r = 0;
	
	escape;
	moveto ##xe, ##ye;
	
	while (1) {
		searchup "<[a-zA-Z!/?]", regular;
		if (!result) break;
		##xr = x; ##yr = y;
		$str = gettext2(column, lineno, column + 4, lineno);
		if (!strstr($str, "<!--")) searchdown "-->";
		else if (!strstr($str, "<?")) searchdown "?>";
		else searchdown "[^ <=>?-]>", regular;
		moveto selendx, selendy;
		if (result && ((##rect && (##xr >= ##xt && ##xr < ##xe && ##yr >= ##yt && x > ##xt && x <= ##xe && y <= ##ye)) || ((!##rect) && ((##yr > ##yt || (##xr >= ##xt && ##yr == ##yt)) && (y < ##ye || (x <= ##xe && y == ##ye)))))) {
			##r = 1;
			beginsel;
			moveto ##xr, ##yr;
			delete;
		} else if (##yr > ##yt || (##xr > ##xt && ##yr == ##yt)) moveto ##xr, ##yr;
		else break;
	}
	
	moveto ##xt, ##yt;
	if (!##r) beep;
	
	goto End;

DeletePair:	//カーソルを含む要素の開始タグと終了タグを削除
	##x = x; ##y = y;
	
	while (1) {
		if (selecting) escape;
		searchup "<(?!" + $ve + ")[a-z][a-z0-9]*( [^>]+)?>", regular, nocasesense;
		if (!result) {	//カーソルを含む要素の開始タグが見つからなければ警告音で終了
			if (x != ##x || y != ##y) moveto ##x, ##y;
			beep;
			goto End;
		}
		##xr = x; ##yr = y;
		$$tag = gettext(x, y, selendx, selendy);	//開始タグ
		##len = strstr($$tag, " ") - 1;	//要素名の長さ
		if (##len < 0) ##len = strlen($$tag) - 2;
		$$en = midstr($$tag, 1, ##len);	//要素名
		$$etag = "</" + $$en + ">";	//終了タグ
		while (1) {
			if (selecting) escape;
			searchdown $$etag;
			if (!result) break;
			moveto selendx, selendy;
			$$str = gettext(##xr, ##yr, x, y);
			call CheckElement $$str, $$en;
			if (##return) break;
		}
		if (result && (##y > ##yr || (##x > ##xr && ##y == ##yr)) && (##y < y || (##x < x && ##y == y))) break;
		moveto ##xr, ##yr;
	}
	
	searchup $$etag;
	delete;
	moveto ##xr, ##yr;
	searchdown2 $$tag;
	delete;
	
	goto End;

CheckElement:	//指定文字列における指定要素のタグの対応を調べる
	call Count $$1, "<" + $$2 + " ";
	##stag = ##return;	//開始タグの数
	call Count $$1, "<" + $$2 + ">";
	##stag = ##stag + ##return;
	call Count $$1, "</" + $$2 + ">";
	##etag = ##return;	//終了タグの数
	##match = 0;
	if (##stag == ##etag) ##match = 1;
	return ##match;

Count:	//文字列の出現回数を調べる
	$$str = $$1;	//検索対象文字列
	##n = strstr($$1, $$2);	//文字列の出現位置
	##len = strlen($$2);	//文字列長
	##i = 0;
	while (##n > -1) {
		##i = ##i + 1;
		$$str = midstr($$str, ##n + ##len);	//未検索文字列
		##n = strstr($$str, $$2);
	}
	return ##i;

End:	//終了処理
	endgroupundo;
	enabledraw;
	endmacro;

範囲選択による削除は、厳密にはタグの先頭と末尾が選択範囲に含まれているかどうかで判定しています。
複数行にわたるタグをBOX選択で削除する場合は、この点に注意してください。

実は、最初はタグ内で実行するとタグを単独で削除する機能もありました。
でも実際に使ってみると、HTMLタグを選択するマクロを使ってタグを削除したほうが早く、結局ほとんど使わない機能となり、むしろ開始タグと終了タグを削除する機能の邪魔になってしまったため、ソースコードも削除した経緯があります。