/**
* HTML整形スクリプト。開いているファイル全体が対象です。
* とてつもなく遅いです。 1000行で1分くらいかかるので注意してください。
*
* [注意事項]
* 途中で止めてしまうと以下の設定が変更されたままになります。
* ・インクリメンタルサーチ - OFF
* ・検索の大文字小文字区別 - 区別しない
*/
// インクリメンタルサーチ情報保存
var incSearchFlag = globalSettings.getBoolValue("incSearch");
// インクリメンタルサーチ解除
globalSettings.setBoolValue( "incSearch", 0 );
// 大文字小文字区別サーチ情報保存
var ignorecaseFlag = globalSettings.getBoolValue("ignorecase");
// 大文字小文字区別サーチ解除
globalSettings.setBoolValue( "ignorecase", 1 );
// 1回でUndoできるように
thisView.openUndoBlock();
// とりあえず整形
thisView.viCommand( "\x1b" );
thisView.viCommand( ":%s/</\\n&/g\n" );
thisView.viCommand( ":%s/>/&\\n/g\n" );
thisView.viCommand( ":g/^\s*$/d\n" );
thisView.viCommand( ":g/^\\s*$/d\n" );
thisView.viCommand( ":%s/^\\s*(.*)\\s*$/\\1/\n" );
// 1行目に移動
thisView.setCursorPos( 1,0 );
// インデント調整
var indentLevel = 0; // インデントを行う数
while( thisView.getCursorPos().line != thisView.getLineCount() ){
var pos = thisView.getCursorPos();
var line = pos.line;
var lineStr = thisView.getLineString( line );
//lineStr = lineStr.substring( pos.offset, lineStr.length() );
if( lineStr.charAt(0) != "\t" ){
if( lineStr.charAt(0) == "<" ){
thisView.viCommand( "mp" ); // 開始位置をpに保存
lineStr =~ /<\??([^>\s]+)/;
var tagName = $1;
var tagSlash = 1; // スラッシュ付きなら-1 無しなら 1
var isFind = 0; // 見つけたら1に
var hitCount = 1; // ヒット数カウント用
var nestCount = 0; // ネスト集計用
var beforePos = pos;
// 検索文字列設定
var searchCmd;
if( tagName.charAt(0) == "/" ){
tagName = tagName.substring( 1, tagName.length() );
searchCmd = "?" + "<\\??[\\s\\/]*" + tagName + "[\\s>]\n";
tagSlash = -1;
}else{
searchCmd = "/" + "<\\??[\\s\\/]*" + tagName + "[\\s>]\n";
tagSlash = 1;
}
// 閉じタグを探さないタグ一覧で在れば閉じタグ無しと判断
var searchFlag = 1;
var tagNameLower = tagName.toLower();
var nonSearchTagArray = {"br", "p", "html", "img", "hr", "option", "area" };
for( var i=0; i<7; i++ ){
if( tagNameLower == nonSearchTagArray[i] ){
searchFlag = 0;
}
}
// <!-- だけは完全一致以外もタグ無し扱い
if( tagNameLower.find( "!--" ) == 0 ){
searchFlag = 0;
}
if( searchFlag ){
// 一度検索する。開始位置のタグが見つかるはず
thisView.viCommand( searchCmd );
while( thisView.isMatched() ) {
var nowPos = thisView.getCursorPos();
var nowLine = thisView.getLineString( nowPos.line );
// ファイルの先頭/終端を越えたら終了
if( (nowPos.line - beforePos.line) * tagSlash < 0 ){
break;
}
nowLine = nowLine.substring( nowPos.offset, nowLine.length() );
nowLine = nowLine.replace( /<[\?%]?/, "" );
if( nowLine.charAt(0) == "/" ) {
hitCount = hitCount - tagSlash;
}else{
hitCount = hitCount + tagSlash;
}
if( hitCount > nestCount ) nestCount = hitCount;
if( hitCount == 0 ) {
// 見つかった
isFind = 1;
break;
}
beforePos = nowPos;
thisView.viCommand( searchCmd );
}
}
if( isFind == 0 ) {
thisView.viCommand( "`p" ); // 元の位置に戻る
thisView.insertText( "\t".repeat(indentLevel) );
}else{
if(tagSlash == -1){
indentLevel += tagSlash;
}
thisView.insertText( "\t".repeat(indentLevel) );
thisView.viCommand( "`p" ); // 元の位置に戻る
thisView.insertText( "\t".repeat(indentLevel) );
if(tagSlash == 1){
indentLevel += tagSlash;
}
}
}else{
thisView.insertText( "\t".repeat(indentLevel) );
}
}else{
indentLevel--;
}
// 1行下に下がる
thisView.setCursorPos( thisView.getCursorPos().line+1, 0 );
}
// インクリメンタルサーチ設定を戻す
globalSettings.setBoolValue( "incSearch", incSearchFlag );
// 大文字小文字区別サーチ設定を戻す
globalSettings.setBoolValue( "ignorecase", ignorecaseFlag );
// マッチ背景を消す
thisView.viCommand( ":cmd 33064\n" );
// 1回でUndoできるように
thisView.closeUndoBlock();