//
// HTML タグ削除マクロ DeleteTag.mac Version 4.07 (2003/04/12)
//
// Made by IKKI http://www18.big.or.jp/~fujiwara/ikki/
//
//------ 設定 ----------------------------------------------------------------
// ▼ 終了タグが省略可能な要素(dt dd li p option td th tr colgroup tbody thead tfoot head body html)について
// (1) 終了タグなし:
$MustOmitted = "";
// (2) 終了タグ省略可:
$MightOmitted = "dt dd li p option td th tr colgroup tbody thead tfoot head body html";
// 説明はドキュメントに書いてあります。わからないときは全部 (2) に入れておいてください。
// ▼ タグ外で実行したらどうするか
// 0:何もしない
// 2:最初に見つけたタグを削除(確認あり)
// 3:最初に見つけたタグを削除(確認なし)
// 4:カーソル位置の要素を削除(確認あり)
// 5:カーソル位置の要素を削除(確認なし)
// 9:任意のコマンドを実行(85行目付近で指定)
#WhereOutside = 4;
// ▼ 範囲選択してたらどうするか
// 1:範囲内に含まれるタグをすべて削除(確認あり)
// 2:範囲内に含まれるタグをすべて削除(確認なし)
#WhereSelecting = 1;
//------ 設定ここまで --------------------------------------------------------
$MustOmitted = " br img hr col input area param basefont base meta link isindex frame " + $MustOmitted + " ";
$MightOmitted = " " + $MightOmitted + " ";
$Delimiter = "[ \\t\\x0a/>]";
$AnyTag = "?[A-Za-z][A-Za-z0-9:_.-]*" + $Delimiter;
#debug = no; // デバッグモード
call Initialize;
if (rectselecting) call RectSelecting;
else if (selecting) call Selecting;
else call NoSelecting;
call Finalize;
endmacro;
NoSelecting: // 範囲選択してない場合
#stc = column; #stl = lineno;
right; // カーソル位置の右側にあるタグも対象とする
call GetFirstTag;
call DeleteTag;
if (#type & 0x10) { // 終了タグのとき
call SeekPairUp;
call DeleteTag;
} else if (#type & 0x03) { // 開始タグのとき
call SeekPairDown;
if (##return) call DeleteTag;
}
movetolineno #stc + 1, #stl;
return;
GetFirstTag: // 対象とするタグを取得
call GetNextTag 0; // 直近のタグを検索(上方向)
call SelectTag;
// タグ外で実行したとき
if (#tdl < #stl || (#tdl == #stl && #tdc < #stc)) {
if (#WhereOutside == 2 || #WhereOutside == 3) {
// 直近のタグを対象とする(ここでは何もしない)
} else if (#WhereOutside == 4 || #WhereOutside == 5) {
// 自要素の開始タグを探す
while ((#type & 0x10) || (!(#type & 0x03))) {
if (#type & 0x10) call SeekPairUp;
call GetNextTag 0;
}
} else {
// キャンセル
movetolineno #stc + 1, #stl;
if (#WhereOutside == 9) {
deletewordall; // 任意のコマンドを指定
}
call Error 0;
}
// 確認
if (#WhereOutside == 2 || #WhereOutside == 4) {
call SelectTag;
enabledraw;
question "このタグを(ペアで)削除しますか?"; if (!result) call Error 0;
if (!#debug) disabledraw;
}
}
return;
DeleteTag: // タグを削除
// 準備: 削除するタグの先頭(「<」の直前)にカーソルを置く
call SelectTag;
if (#debug) { question "削除?"; if (!result) endmacro; }
delete;
// 桁補正
if (#stl > #tpl || (#stl == #tpl && #stc > #tpc)) { // <→ > 影響範囲
if (#stl < #tdl || (#stl == #tdl && #stc < #tdc)) #stc = #tpc; // < ←> タグ内
else if (#stl == #tdl) #stc = #stc - #tdc + #tpc; // < >→ タグ外
}
// 行補正
if (#stl > #tpl) { // <↓ > 影響範囲
if (#stl < #tdl) #stl = #tpl; // < ↑> タグ内
else #stl = #stl - #tdl + #tpl; // < >↓ タグ外
}
return;
SelectTag: // タグを選択
// 準備: タグの先頭(「<」の直前)にカーソルを置く
// 効果: #tpc, #tpl, #tdc, #tdl = 選択範囲 (column, lineno)
if (code != '<') call Error 9;
#tpc = column; #tpl = lineno;
searchdown ">"; if (!result) call Error 3;
right;
#tdc = column; #tdl = lineno;
beginsel;
movetolineno #tpc + 1, #tpl;
endsel;
return;
SeekPairDown: // 対応する終了タグを探す
#searchhere = yes; // 初回はカーソル位置から検索開始(DeleteTag.mac 専用)
while (true) {
if (#type & 0x10) { // 終了タグのとき
while ($name != $names[#d]) { // 食い違ったらスタック巻き戻し
if (#debug) call Confirm "違う";
#d = #d - 1;
if (#d < 1) return false; // 見つからなかったらそこまで
}
#d = #d - 1; // 外へ
if (#d < 1) return true;
if (#debug) call Confirm "外へ";
} else if (#type & 0x03) { // 開始タグのとき
#d = #d + 1; // 中へ
$names[#d] = $name; // スタックに積む
if (#type & 0x02) { // 終了タグあり
call IgnoreCase $name;
$seeks[#d] = $$return;
} else {
$seeks[#d] = "";
}
if (#debug) call Confirm "中へ";
}
call GetNextTag 1; // 次を検索(下方向)
}
call Error 9;
SeekPairUp: // 対応する開始タグを探す
while (true) {
if (#type & 0x10) { // 終了タグのとき
#d = #d + 1; // 中へ
$names[#d] = $name; // スタックに積む
if (#type & 0x02) { // 終了タグあり
call IgnoreCase $name;
$seeks[#d] = $$return;
} else { // 終了タグ省略可/終了タグなし(設定ミスを考慮)
$seeks[#d] = "";
}
if (#debug) call Confirm "中へ";
} else if (#type & 0x03) { // 開始タグのとき
if ($name != $names[#d]) {
if (#type & 0x02) call Error 2; // else 無視して次へ
} else {
#d = #d - 1; // 外へ
if (#d < 1) return true; // 抜ける
if (#debug) call Confirm "外へ";
}
}
call GetNextTag 0; // 次を検索(上方向)
}
call Error 9;
IgnoreCase: // 大文字小文字を区別しない正規表現を生成
// 引数: $$1 = 小文字
// 返り値: $$return = 正規表現
##i = strlen($$1);
while (##i) { // およそ 0.44ms/char
##c = ascii(rightstr($$1, ##i));
if (##c < 'a' || ##c > 'z') $$r = $$r + char(##c); // メタキャラクタは考慮してない
else $$r = $$r + "[" + char(##c) + char(##c - 32) + "]";
##i = ##i - 1;
}
return $$r;
GetNextTag: // 次のタグを検索・取得
// 準備: #seeks[#d] = 検索語(正規表現) "":不特定のタグ
// 引数: ##1 = 0: 上方向 != 0: 下方向
// 効果: #type = ビットフラグ
// ___x ____ = 1:終了タグ 0:開始タグ
// ____ __xx = 00:終了タグなし 01:終了タグ省略可 10:終了タグあり
// $name = 要素名(小文字)
if ($seeks[#d] == "") setsearch $AnyTag, 0x10;
else setsearch "?" + $seeks[#d] + $Delimiter, 0x10;
if (##1) {
if (#searchhere) { finddown2; #searchhere = no; } // DeleteTag.mac 専用
else finddown;
} else findup;
if (!result) call Error 1;
if (#debug) { enabledraw; question "発見"; if (!result) endmacro; }
##tpx = x; ##tpy = y; escape;
right;
if (code == '/') {
#type = #type | 0x10;
right;
} else {
#type = #type & 0xef;
}
if ($seeks[#d] == "") {
$name = "";
while (true) {
if (code >= 'A' && code <= 'Z') $name = $name + char(code + 32); // 小文字化
else if (code <= ' ' || code == '/' || code == '>') break; // 区切り文字
else $name = $name + char(code); // そのまま
right;
}
if (strstr($MustOmitted, " " + $name + " ") >= 0) #type = #type & 0xfc; // 終了タグなし
else if (strstr($MightOmitted, " " + $name + " ") >= 0) #type = #type & 0xfc | 0x01; // 終了タグ省略可
else #type = #type & 0xfc | 0x02; // 終了タグあり
}
if (#debug) message "$name = '" + $name + "'\n#type = " + hex(#type);
moveto ##tpx, ##tpy;
#c = #c + 1;
if (#c == 20) title "探索中...";
return;
Selecting: // 範囲選択してる場合
if (#WhereSelecting == 1) {
question "範囲内に含まれるすべてのタグを削除します。\nよろしいですか?";
if (!result) call Error 0;
}
#spx = seltopx; #spy = seltopy; #sdx = selendx; #sdy = selendy; escape;
moveto #spx, #spy; #spl = lineno; #spc = column;
moveto #sdx, #sdy; if (column == 0) { up; golineend2; } #sdl = lineno; #sdc = column;
while (true) {
searchup $AnyTag, regular; if (!result) break;
#tpl = lineno; #tpc = column;
if (lineno < #spl || (lineno == #spl && column < #spc)) break; // タグ先頭が選択範囲外
searchdown ">"; if (!result) call Error 3;
right;
if (lineno > #sdl || (lineno == #sdl && column > #sdc)) { movetolineno #tpc + 1, #tpl; continue; } // タグ末尾が選択範囲外
beginsel;
movetolineno #tpc + 1, #tpl;
if (#debug) { question "削除?"; if (!result) endmacro; }
delete;
}
moveto #spx, #spy;
return;
RectSelecting: // BOX 選択してる場合
if (#WhereSelecting == 1) {
question "BOX 範囲内に含まれるすべてのタグを削除します。\nよろしいですか?";
if (!result) call Error 0;
}
#spx = seltopx; #spy = seltopy; #sdx = selendx; #sdy = selendy; escape;
moveto #sdx, #sdy;
while (true) {
searchup $AnyTag, regular; if (!result) break;
#tpx = x; #tpy = y;
if (y < #spy || (y == #spy && x < #spx)) break; // タグ先頭が選択範囲外
if (x < #spx || x >= #sdx) continue; //
searchdown ">"; if (!result) call Error 3;
right;
if (y > #sdy || (y <= #sdy && x > #sdx)) { moveto #tpx, #tpy; continue; } // タグ末尾が選択範囲外
// タグが複数行の場合
if (y > #tpy) {
#tdx = x; #tdy = y;
##covered = true;
while (y > #tpy) {
golinetop;
if (x < #spx) { ##covered = false; break; } // タグ内の行頭が選択範囲外
up; golineend;
if (x > #sdx) { ##covered = false; break; } // タグ内の行末が選択範囲外
}
if (!##covered) { moveto #tpx, #tpy; continue; }
moveto #tdx, #tdy;
}
beginsel;
moveto #tpx, #tpy;
if (#debug) { question "削除?"; if (!result) endmacro; }
delete;
}
moveto #spx, #spy;
return;
Initialize: // 初期化
#starttime = tickcount;
#orgc = column; #orgl = lineno;
$searchbuffer = searchbuffer; #searchoption = searchoption;
if (!#debug) disabledraw;
return;
Finalize: // 後始末
setsearch $searchbuffer, #searchoption;
enabledraw;
return;
Error: // エラー処理
// 引数: ##1 = エラー番号
// 0: キャンセルした
// 1: タグが見つからない
// 2: ネスト外へ出た
// 3: 「>」が見つからない
// 9: while(true) を抜けた
enabledraw;
if (##1 == 0) {
escape;
movetolineno #stc + 1, #stl;
} else if (##1 == 1) {
message "対応するタグが見つかりません\n" + str(tickcount - #starttime) + "ms / " + str(#c) + "tags";
} else if (##1 == 2) {
question str(lineno) + ": <" + leftstr("/", #type & 0x10) + $name + "> の終了タグが見あたりません\n無視して続けますか?";
if (result) { if (!#debug) disabledraw; return; }
} else if (##1 == 3) {
message "「>」が見つかりません";
} else if (##1 == 9) {
message "マクロが予想外の動作をしました";
}
movetolineno #orgc + 1, #orgl;
call Finalize;
endmacro;
Confirm: // 動作確認(デバッグ用)
##p = 1;
while (##p <= #d) { // スタックトレース
$$stuck = $$stuck + "\n" + str(##p) + ": " + $names[##p] + "\t" + $seeks[##p];
##p = ##p + 1;
}
question "<" + leftstr("/", #type & 0x10) + $name + ">\t" + $$1 + "\n" + $$stuck;
if (!result) endmacro;
return;
// (C) IKKI 2002