Eclipse風コメントアウト(改)

提供: MeryWiki
ナビゲーションに移動 検索に移動

概要[編集]

Eclipse風なコメントアウト <=> コメントの除去を行います。

ksさんの作成された、Eclipse風コメントアウトは、私にとって欠かせないツールです。

便利に使わせていただく一方、細かい挙動が気になって変更したり、機能を追加しているうちに、すっかり別物になってしまいました。

オリジナルを作成されたksさんに感謝するとともに、せっかく作成したので改造版をここに公開します。

注意事項[編集]

Shiftキーの状態を取得するためにshell.GetKeyStateメソッドを使用しているため、Mery Ver 3.7.2以降で動作します。

ソースコード[編集]

JavaScript[編集]

#icon = "_Comment.ico"
#title = "選択行コメントアウト"

// -----------------------------------------------------------------------------
// Eclipse風なコメントアウト
// 複数行一括コメントアウト、復帰マクロ
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 2) 空白行はコメントアウトしない
// 3) インデントは選択行の範囲で一番左(タブ幅単位)に合わせる
// 4) 選択範囲全体がコメントアウトされている場合は復帰
//
// Copyright (c) ks. All Rights Reserved.
// www:		http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------
// a) 最終行の先頭までの選択状態では、最終行は処理範囲外にする(行選択対応)
// b) コメント文字の種類を追加(Mery標準で単一行コメント可能な編集モード全て対応)
// c) スペースが含まれるコメント文字に対応
// d) コメント文字が正規表現文字でも正しく動作するようにした
// e) コメント文字不明時、SHIFTキー押下起動時はコメント文字を入力できるようにした
// f) 選択方向を維持するようにした(下から上への選択対応)
// g) 空白行で実行するとUndoされてしまう問題に対処
// h) OutputBarにフォーカスがある場合に処理できない問題に対処
//
// Improved by pizz
// -----------------------------------------------------------------------------

var doc = editor.ActiveDocument;
var COM = ""; // 単一行コメント
var TAGKEY = "pizzComment";

switch (doc.Mode.toLowerCase()) {
	case "bat":
		COM = "rem ";
		break;
	case "c#":
	case "c++":
	case "coldfusion":
	case "delphi":
	case "java":
	case "javascript":
	case "jsp":
	case "php":
	case "uwsc":
		COM = "// ";
		break;
	case "hsp":
	case "ini":
	case "x86 assembler":
		COM = "; ";
		break;
	case "perl":
	case "perlscript":
	case "powershell":
	case "python":
	case "rhtml":
	case "ruby":
		COM = "# ";
		break;
	case "sql":
		COM = "-- ";
		break;
	case "tex":
		COM = "% ";
		break;
	case "vbscript":
	case "visualbasic":
		COM = "'";
		break;
}

// タグ設定を取得
var comSelected = "";
if (document.Tag.exists(TAGKEY)) {
	comSelected = document.Tag(TAGKEY);
}
if (comSelected == "") {
	comSelected = COM;
}
var comTrim = comSelected.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字

// SHIFTキー状態を取得
var shift = shell.GetKeyState(0x10);

// コメント文字の入力を受ける
if (comTrim == "" || shift < 0) {
	var comInput = "// ";
	if (comTrim != "") {
		comInput = comSelected;
	}

	comInput = prompt("コメント文字を指定してください", comInput);

	// キャンセルされた場合
	if (!comInput) {
		Quit();
	}

	comTrim = comInput.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字
	if (comTrim != "") {
		comSelected = comInput;
		document.Tag(TAGKEY) = comSelected;
	}
}

if (comTrim != "") {
	var meGetLineLogical = 0;
	var regOrg = new RegExp("^[ \\t]*" + comSelected.replace(/\W/g, "\\$&"));
	var regTrim = new RegExp("^[ \\t]*" + comTrim.replace(/\W/g, "\\$&"));
	var scrollY = window.ScrollY;
	var sel = doc.Selection;
	var st = sel.GetTopPointY(mePosLogical);
	var ed = sel.GetBottomPointY(mePosLogical);
	var ac = sel.GetActivePointY(mePosLogical);
	if (st != ed && sel.GetBottomPointX(mePosLogical) == 1) {
		// 複数行選択、最下行選択位置が行頭の場合は、最終行は除外
		ed--;
	}
	var tab = GetTabSpace();

	sel.SetActivePoint(mePosLogical, doc.GetLine(ed, meGetLineLogical).length + 1, ed);
	sel.SetAnchorPoint(mePosLogical, 1, st);
	var lines = sel.Text.split("\n");
	if (sel.Text.length > 0) {
		sel.Untabify();
	}
	var linesWithoutTab = sel.Text.split("\n");
	if (sel.Text.length > 0) {
		doc.Undo();
	}

	// インデント取得
	var indent = -1;
	var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
	for (var i = 0, len = linesWithoutTab.length; i < len; i++) {
		var line = linesWithoutTab[i];
		var left = line.search(/[^ ]/);
		if (left >= 0 && (indent < 0 || left < indent)) {
			// インデントはタブ幅単位(左寄せ)
			indent = Math.floor(left / tab) * tab;
		}
		if (left >= 0) {
			// コメント行判定
			if (!existNotCommentLine && line.search(regTrim) == -1) {
				existNotCommentLine = true;
			}
		}
	}

	var txt = "";
	var changed = false;
	if (existNotCommentLine) {
		// コメントアウト
		for (var i = 0, len = lines.length; i < len; i++) {
			var line = lines[i] + "\n";
			// 空白行はコメントアウトしない
			if (line.search(/[^ \t\n]/) == -1) {
				txt += line;
				continue;
			}

			// 挿入位置をタブと空白を考慮して決定
			var index = 0, j;
			for (j = 0; index < indent; j++) {
				// indent の範囲には半角スペースかタブしかない
				if (line.charAt(j) == " ") {
					index += 1;
				} else {
					index += tab - (index % tab);
				}
			}
			txt += line.substring(0, j) + comSelected + line.substring(j);
			changed = true;
		}
	} else {
		// コメントから復帰
		for (var i = 0, len = lines.length; i < len; i++) {
			var line = lines[i] + "\n";
			if (line.match(regTrim)) {
				if (line.match(regOrg)) {
					txt += line.replace(comSelected, ""); // 先頭のコメント(空白付き)の削除
				} else {
					txt += line.replace(comTrim, ""); // 先頭のコメント(空白なし)の削除
				}
				changed = true;
			} else {
				txt += line;
			}
		}
	}

	// コメントアウト部分を書き換えて、全体を選択
	if (doc.GetLine(ed + 1, meGetLineWithNewLines) == "") {
		txt = txt.substring(0, txt.length - 1); // 最後の改行は除去
	}
	if (ac == st) {
		// 下から上への選択状態
		sel.SetActivePoint(mePosLogical, 1, st);
		sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
		if (changed) {
			sel.Text = txt;
		}
		sel.SetActivePoint(mePosLogical, 1, st);
		sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
	} else {
		// 上から下への選択状態
		sel.SetActivePoint(mePosLogical, 1, ed + 1);
		sel.SetAnchorPoint(mePosLogical, 1, st);
		if (changed) {
			sel.Text = txt;
		}
		sel.SetAnchorPoint(mePosLogical, 1, st);
	}
	window.ScrollY = scrollY;
}

//========================================
// 関数
//========================================
// タブ幅を取得
function GetTabSpace() {
	var doc = editor.ActiveDocument;
	var sel = doc.Selection;
	var saved = doc.Saved;
	sel.EndOfDocument();
	doc.Write("\n\t");
	sel.SetAnchorPoint(mePosLogical, sel.GetActivePointX(mePosLogical) - 1, sel.GetActivePointY(mePosLogical));
	sel.Untabify();
	var n = sel.Text.length;
	doc.Undo();
	doc.Undo();
	doc.Saved = saved;

	return n;
}

QuickJS / V8[編集]

このスクリプトを使用するときは、ファイルの先頭に#language = "quickjs"または#language = "V8"を記述してください。

#language = "quickjs"
#icon = "_Comment.ico"
#title = "選択行コメントアウト"

// -----------------------------------------------------------------------------
// Eclipse風なコメントアウト
// 複数行一括コメントアウト、復帰マクロ
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 2) 空白行はコメントアウトしない
// 3) インデントは選択行の範囲で一番左(タブ幅単位)に合わせる
// 4) 選択範囲全体がコメントアウトされている場合は復帰
//
// Copyright (c) ks. All Rights Reserved.
// www:		http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------
// a) 最終行の先頭までの選択状態では、最終行は処理範囲外にする(行選択対応)
// b) コメント文字の種類を追加(Mery標準で単一行コメント可能な編集モード全て対応)
// c) スペースが含まれるコメント文字に対応
// d) コメント文字が正規表現文字でも正しく動作するようにした
// e) コメント文字不明時、SHIFTキー押下起動時はコメント文字を入力できるようにした
// f) 選択方向を維持するようにした(下から上への選択対応)
// g) 空白行で実行するとUndoされてしまう問題に対処
// h) OutputBarにフォーカスがある場合に処理できない問題に対処
//
// Improved by pizz
// -----------------------------------------------------------------------------

var doc = editor.ActiveDocument;
var COM = ""; // 単一行コメント
var TAGKEY = "pizzComment";

switch (doc.Mode.toLowerCase()) {
	case "bat":
		COM = "rem ";
		break;
	case "c#":
	case "c++":
	case "coldfusion":
	case "delphi":
	case "java":
	case "javascript":
	case "jsp":
	case "php":
	case "uwsc":
		COM = "// ";
		break;
	case "hsp":
	case "ini":
	case "x86 assembler":
		COM = "; ";
		break;
	case "perl":
	case "perlscript":
	case "powershell":
	case "python":
	case "rhtml":
	case "ruby":
		COM = "# ";
		break;
	case "sql":
		COM = "-- ";
		break;
	case "tex":
		COM = "% ";
		break;
	case "vbscript":
	case "visualbasic":
		COM = "'";
		break;
}

// タグ設定を取得
var comSelected = "";
if (document.Tag.exists(TAGKEY)) {
	comSelected = document.Tag[TAGKEY];
}
if (comSelected == "") {
	comSelected = COM;
}
var comTrim = comSelected.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字

// SHIFTキー状態を取得
var shift = shell.GetKeyState(0x10);

// コメント文字の入力を受ける
if (comTrim == "" || shift < 0) {
	var comInput = "// ";
	if (comTrim != "") {
		comInput = comSelected;
	}

	comInput = prompt("コメント文字を指定してください", comInput);

	// キャンセルされた場合
	if (!comInput) {
		Quit();
	}

	comTrim = comInput.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字
	if (comTrim != "") {
		comSelected = comInput;
		document.Tag[TAGKEY] = comSelected;
	}
}

if (comTrim != "") {
	var meGetLineLogical = 0;
	var regOrg = new RegExp("^[ \\t]*" + comSelected.replace(/\W/g, "\\$&"));
	var regTrim = new RegExp("^[ \\t]*" + comTrim.replace(/\W/g, "\\$&"));
	var scrollY = window.ScrollY;
	var sel = doc.Selection;
	var st = sel.GetTopPointY(mePosLogical);
	var ed = sel.GetBottomPointY(mePosLogical);
	var ac = sel.GetActivePointY(mePosLogical);
	if (st != ed && sel.GetBottomPointX(mePosLogical) == 1) {
		// 複数行選択、最下行選択位置が行頭の場合は、最終行は除外
		ed--;
	}
	var tab = GetTabSpace();

	sel.SetActivePoint(mePosLogical, doc.GetLine(ed, meGetLineLogical).length + 1, ed);
	sel.SetAnchorPoint(mePosLogical, 1, st);
	var lines = sel.Text.split("\n");
	if (sel.Text.length > 0) {
		sel.Untabify();
	}
	var linesWithoutTab = sel.Text.split("\n");
	if (sel.Text.length > 0) {
		doc.Undo();
	}

	// インデント取得
	var indent = -1;
	var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
	for (var i = 0, len = linesWithoutTab.length; i < len; i++) {
		var line = linesWithoutTab[i];
		var left = line.search(/[^ ]/);
		if (left >= 0 && (indent < 0 || left < indent)) {
			// インデントはタブ幅単位(左寄せ)
			indent = Math.floor(left / tab) * tab;
		}
		if (left >= 0) {
			// コメント行判定
			if (!existNotCommentLine && line.search(regTrim) == -1) {
				existNotCommentLine = true;
			}
		}
	}

	var txt = "";
	var changed = false;
	if (existNotCommentLine) {
		// コメントアウト
		for (var i = 0, len = lines.length; i < len; i++) {
			var line = lines[i] + "\n";
			// 空白行はコメントアウトしない
			if (line.search(/[^ \t\n]/) == -1) {
				txt += line;
				continue;
			}

			// 挿入位置をタブと空白を考慮して決定
			var index = 0, j;
			for (j = 0; index < indent; j++) {
				// indent の範囲には半角スペースかタブしかない
				if (line.charAt(j) == " ") {
					index += 1;
				} else {
					index += tab - (index % tab);
				}
			}
			txt += line.substring(0, j) + comSelected + line.substring(j);
			changed = true;
		}
	} else {
		// コメントから復帰
		for (var i = 0, len = lines.length; i < len; i++) {
			var line = lines[i] + "\n";
			if (line.match(regTrim)) {
				if (line.match(regOrg)) {
					txt += line.replace(comSelected, ""); // 先頭のコメント(空白付き)の削除
				} else {
					txt += line.replace(comTrim, ""); // 先頭のコメント(空白なし)の削除
				}
				changed = true;
			} else {
				txt += line;
			}
		}
	}

	// コメントアウト部分を書き換えて、全体を選択
	if (doc.GetLine(ed + 1, meGetLineWithNewLines) == "") {
		txt = txt.substring(0, txt.length - 1); // 最後の改行は除去
	}
	if (ac == st) {
		// 下から上への選択状態
		sel.SetActivePoint(mePosLogical, 1, st);
		sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
		if (changed) {
			sel.Text = txt;
		}
		sel.SetActivePoint(mePosLogical, 1, st);
		sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
	} else {
		// 上から下への選択状態
		sel.SetActivePoint(mePosLogical, 1, ed + 1);
		sel.SetAnchorPoint(mePosLogical, 1, st);
		if (changed) {
			sel.Text = txt;
		}
		sel.SetAnchorPoint(mePosLogical, 1, st);
	}
	window.ScrollY = scrollY;
}

//========================================
// 関数
//========================================
// タブ幅を取得
function GetTabSpace() {
	var doc = editor.ActiveDocument;
	var sel = doc.Selection;
	var saved = doc.Saved;
	sel.EndOfDocument();
	doc.Write("\n\t");
	sel.SetAnchorPoint(mePosLogical, sel.GetActivePointX(mePosLogical) - 1, sel.GetActivePointY(mePosLogical));
	sel.Untabify();
	var n = sel.Text.length;
	doc.Undo();
	doc.Undo();
	doc.Saved = saved;

	return n;
}

変更履歴[編集]

  • 1.0.2 (2020-03-15)
    • Mery 3.0.0以降対応版の追加(document.Tagプロパティを使用)
  • 1.0.1 (2019-04-12)
    • window.Quit() メソッドの使用排除
  • 1.0.0 (2019-03-04)
    • 新規作成
スポンサーリンク