スポンサーリンク

サクラエディタのマクロで,CSSを自動整形しよう


サクラエディタ上で,CSSを自動整形したい。


例えば,エディタ上に

div.hatena-asin-recommend {
margin:4px 10px;
padding:5px 4px;
text-align:left;
width:96%;
}
div.hatena-asin-recommend a {
border:medium none;
text-decoration:none;
}
div.hatena-asin-recommend-item-1 {
float:left;
width:49%;
}

のようなCSSが表示されている。

ここで,ショートカットキーを押すと

div.hatena-asin-recommend {
  margin     : 4px 10px;
  padding    : 5px 4px;
  text-align : left;
  width      : 96%;
}
div.hatena-asin-recommend a {
  border          : medium none;
  text-decoration : none;
}
div.hatena-asin-recommend-item-1 {
  float : left;
  width : 49%;
}

のように,半角スペースでインデントしてくれる。


このような,IDEに大抵付いているコードフォーマット機能を,サクラエディタでも利用したい。


そのためには,コードフォーマットするようなマクロを作ってエディタから呼び出せばよい。


以下はその手順。



(1)マクロを入手して,保存する


以下のコードをコピペして,mod_css.js として保存する。



/*
	CSSを整形するマクロ (サクラエディタ用)
	
	※行内での *//*というコメントの区切りは許容しない。
	※単独行のブロックを単独行でコメントアウトすることは許容しない。/*a{b:c}*/のような。
*/


// ---------- 解析用のメソッド ---------- 


var wsh = new ActiveXObject("WScript.Shell");


// メイン
function main()
{
	// 現在見ている行のタイプを表すフラグ

	// コメントの開始から,コメントの終了まで
	var inside_comment = false;
	// ブロックの開始から,ブロックの終了まで
	var inside_block   = false;
		// CSS構文規則
		// http://hp.vector.co.jp/authors/VA022006/css/syntax.html


	// 行ごとに解析
	var line_count = Editor.GetLineCount(0);
		// http://www.geocities.jp/maru3128/SakuraMacro/reference/other/S_GetLineCount.html
		log( "全" + line_count + "行を変換します。" );
	var block_lines = [];
	for( var i = 1; i <= line_count; i ++ )
	{
		// 行を取得
		var line = Editor.GetLineStr( i );
			// http://www.geocities.jp/maru3128/SakuraMacro/sample/SampleGetLineStr.html
			log( i + " 行目:" + line );
		
		// コメント中か?
		if( inside_comment )
		{
			save_line( line );
			
			// コメントの終わりが来たか
			if( comment_ending( line ) )
			{
				inside_comment = false;
					log( "コメントが終了しました。" )
			}
			else
			{
				log( "コメントが継続しています。" )
			}
			
			continue;
		}
		// 複数行に渡るブロック内
		else if( inside_block )
		{
			// ブロックの終わりが来たか
			if( block_ending( line ) )
			{
					log( "ブロックが終わりました。" );

				// 一時保管済みの全要素を整形して保存
				modified_lines = modify_block_lines( block_lines );
				save_lines( modified_lines );
				
				// 一時保管内容をリセット
				block_lines= [];

				inside_block = false;
				save_line( line );
			}
			else
			{
				// この行を配列に一時保管
				block_lines.push( line );
					// ブロックの終わりが来ない限り,
					// コメントも保管される。
					log( "ブロックが継続しています。" );
			}
			continue;
		}
		// コメント外・ブロック外で,ブロックが始まったか?
		else if( block_beginning( line ) )
		{
			save_line( line );
			inside_block = true;
				log( "ブロックが開始しました。" );
			
			// 行内ですぐにブロックが終わっているか?
			if( block_ending( line ) )
			{
				inside_block = false;
					log( "ブロックが行内で終了しました。" );
			}
			
			continue;
		}
		// コメント外・ブロック外で,コメントが始まった
		else if( comment_beginning( line ) )
		{
			save_line( line );
			inside_comment = true;
				log( "コメントが開始しました。" );
			
			// 行内ですぐにコメントが終わっているか
			if( comment_ending( line ) )
			{
				inside_comment = false;
					log( "コメントが行内で終了しました。" );
			}
			continue;
		}
		// その他の行(空行 or ディレクティブ)
		else
		{
			save_line( line );
				log( "この行を意識する必要はありません。" );
		}
	}
	
	// 解析結果をエディタ上に反映させる
	update_editor();
	
	return;
}


// 以下はサブ処理:


// 行を結果に保存。変換済み,もしくは変換の必要がない。
function save_line( line )
{
	result_lines.push( line );
}
var result_lines = [];


// 複数行を結果に保存
function save_lines( lines )
{
	for( var i = 0; i < lines.length; i ++ )
	{
		save_line( lines[ i ] );
	}
}


// 行内でコメントが始まっているか
function comment_beginning( line )
{
	return ( line.match( "/\\*" ) != null );
}


// 行内でコメントが終わっているか
function comment_ending( line )
{
	return ( line.match( "\\*/" ) != null );
}


// 行内でブロックが始まっているか
function block_beginning( line )
{
	return ( line.match( "{" ) != null );
}


// 行内でブロックが終わっているか
function block_ending( line )
{
	return ( line.match( "}" ) != null );
}


// ブロックを整形
function modify_block_lines( block_lines )
{
	// まず1行ごとにスペースを調整
	for( var i = 0; i < block_lines.length; i ++ )
	{
		var old_line = block_lines[ i ];
		var new_line = normalize_space( old_line );
		block_lines[ i ] = new_line;
	}

	// : がある最も右寄りの位置を算出
	var max_colon_position = -1;
	for( var i = 0; i < block_lines.length; i ++ )
	{
		var line = block_lines[ i ];
		var colon_position = line.indexOf( ":" );
		if( max_colon_position < colon_position )
		{
			max_colon_position = colon_position;
		}
	}
		log( "ブロック内のコロンの位置を" + max_colon_position + "文字目にそろえます。" );

	// : の位置を右寄りにそろえる
	for( var i = 0; i < block_lines.length; i ++ )
	{
		var old_line = block_lines[ i ];
		var colon_position = old_line.indexOf( ":" );
		if( max_colon_position > colon_position )
		{
			// 挿入すべき半角スペースを生成
			var lacking_spaces_before_colon = max_colon_position - colon_position;
			var additional_spaces = new Array( lacking_spaces_before_colon + 1 ).join(" ");
			
			// : の位置をずらして書き換え
			var new_line = old_line.replace( ":", additional_spaces + ":" );
			block_lines[ i ] = new_line;
				log( "「" + new_line + "」に加工しました。" );
		}
	}
	
	return block_lines;
}



// 行内のスペースを標準に調整します。
function normalize_space( line )
{
	var modified_line = line
		.replace( /^[ \t]*(?![\\/\\* \t])/, "  " )
			 // 行内容の始まりがコメントの開始かコメントの終端でなければ,
			 // 行頭のスペースを2つにそろえる
		.replace( / *:/, " :" ) // コロン左のスペースを1つにそろえる
		.replace( /: */, ": " ) // コロン右のスペースを1つにそろえる
	;
		log( "「" + line + "」を「" + modified_line + "」に正規化" );
	return modified_line;
}


function update_editor()
{
	Editor.SelectAll();
		// http://www.geocities.jp/maru3128/SakuraMacro/reference/select/S_SelectAll.html
	Editor.InsText( result_lines.join("") );
		// http://www.geocities.jp/maru3128/SakuraMacro/reference/clipboard/S_InsText.html
		// 各lineは行末の改行を含んでいるので,改行を付加し直す必要はない
}


function log( str )
{
	// 実行状況をモニタしたい場合は,ここのコメントアウトを外します。
	//wsh.Popup( str );
}



// ---------- 実行 ---------- 


main();


コードの補足:

  • WSH/JScriptで記述されている。
  • 思いっきり手続き型のコードで,しかも字句単位ではなく行単位の解析だが,CSSは行ごとのまとまりが良いのでそこは許容されたい。
  • normalize_space()の中の正規表現で,(?!〜〜) となっている部分は,幅ゼロの否定先読み。以下URLを参照。行内容の始まりがコメント関連の場合は,行頭のスペースを調整しない,という意味。

javaにマッチしてjavascriptにマッチさせないためには java(?!script) と書く
http://oshiete1.goo.ne.jp/qa1547202.html

(2)エディタにマクロを登録する

サクラのインストールフォルダに行く。

C:\Program Files\sakura

macroというディレクトリを作る。

C:\Program Files\sakura\macro

そこに,先ほどのjsファイルを設置。

C:\Program Files\sakura\macro\mod_css.js


サクラを開いて,下記のように操作する。

  1. メニューバーの「設定」の「共通設定」を開く。
  2. 「マクロ」というタブへ。
  3. 右上の「参照」ボタンの左が「C:\Program Files\sakura\macro\」になっていることを確認。
  4. 適当な番号を選択。
  5. 名前に「CSS整形」と入力。
  6. Fileから「mod_css.js」を選択。
  7. 「マクロを実行するたびにファイルを読み込み直す」にチェック。
  8. 「設定」ボタンを押下。
  9. 「OK」をクリック。


これで,サクラのメニューバーの「ツール」の「登録済みマクロ」から,「CSS整形」というマクロを実行できるようになった。

(3)キー割り当て

ショートカットキー一発で,上記のマクロを呼び出せるようにしたい。

サクラを開いて,以下のように操作する。

  1. メニューバーの「設定」の「共通設定」を開く。
  2. 「キー割り当て」というタブへ。
  3. 「種別」プルダウンから,「外部マクロ」を選択。
  4. 左側のボックスから,「CSS整形」のマクロを選択。
  5. 「Ctrl」というチェックボックスをチェックし,右側のボックスから「Ctrl+F4」を選択。
  6. 「割付」ボタンを押下。
  7. 「OK」をクリック。


これで,今後は「Ctrl+F4」を押下すれば,表示中のCSSを整形できる。


試してみよう


テスト用のスタイルシート。これをサクラエディタ上にコピペしてみる。

/* CSS */

/*
hoge{
  1:2
  3:4
}
*/


body {
  color: black;
  background-color: white;
  font-size: medium;
}

body {
  background-color   : white;

  color: black;
  font-size: medium;
}

body {
  color:black;
}


body {
  color: black;
  background-color: white;
  /* comment */
  /* comment : comment */
  font-size: medium; /* comment */
  font-size: medium; /* comment : comment */
}


body {
  color: black;
/*
  background-color: white;
*/
  font-size: medium;
  color: black;
/*
  background-color: white;
/*
  font-size: medium;
*/

}


/*
body {
  color: black;
/**/
body {
  color: black;
}



そして,Ctrl + F4を押してみる。

整形結果:


/* CSS */

/*
hoge{
  1:2
  3:4
}
*/


body {
  color            : black;
  background-color : white;
  font-size        : medium;
}

body {
  background-color : white;
  
  color            : black;
  font-size        : medium;
}

body {
  color : black;
}


body {
  color            : black;
  background-color : white;
  /* comment */
  /* comment       : comment */
  font-size        : medium; /* comment */
  font-size        : medium; /* comment : comment */
}


body {
  color            : black;
/*
  background-color : white;
*/
  font-size        : medium;
  color            : black;
/*
  background-color : white;
/*
  font-size        : medium;
*/
  
}


/*
body {
  color: black;
/**/
body {
  color : black;
}




※ブロック外では,コメント行は整形されない。

※ブロック内では,コメント行は,コロンを含む部分だけが整形される。



補足

もし整形ルールが気になったら,マクロの内容を自分で書き換えてもOK。

マクロの作成方法の初歩は,以下を参照。

サクラエディタでのマクロ作成方法  (WSH版)
http://language-and-engineering.hatenablog.jp/entry/20081021/1224511689