「Eclipse風コメントアウト(改)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
MSY-07 (トーク | 投稿記録)
セクションの修正
MSY-07 (トーク | 投稿記録)
 
(同じ利用者による、間の16版が非表示)
8行目: 8行目:
オリジナルを作成されたksさんに感謝するとともに、せっかく作成したので改造版をここに公開します。
オリジナルを作成されたksさんに感謝するとともに、せっかく作成したので改造版をここに公開します。


== 注意事項 ==
Mery Ver 3.7.2未満のソースコードでは、Shiftキーの状態を取得するために、[[GetKeyState.exe(キー状態取得実行ファイル)]]を使用しています。本体マクロと併せて上記実行ファイルも必要になります。


Shiftキーの状態を取得するために、[[GetKeyState.exe(キー状態取得実行ファイル)]]を使用しています。
なお、Mery Ver 3.7.2以降のソースコードでは[[マクロリファレンス:3:Shell オブジェクト#GetKeyState メソッド|shell.GetKeyStateメソッド]]を使用しているため、GetKeyState.exeは必要ありません。


本体マクロと併せて上記実行ファイルも必要になります。
== 変更履歴 ==
* 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)
** 新規作成


zipファイルをダウンロードしたら、ファイルのプロパティ画面で「ブロックの解除」を行ってください。
== ソースコード ==
(これをしないと実行時に警告が表示されることがあります)
=== Ver 3.7.2以降 ===
このスクリプトはMery Ver 3.7.2以降対応版です。Mery Ver 3.7.2未満の環境では、Ver 3.0.0以降またはVer 3.0.0未満対応のスクリプトを利用してください。


その後、zipファイルを展開して、Macrosフォルダーに配置してください。
<syntaxhighlight lang="javascript" copy>
#icon = "_Comment.ico"
#title = "選択行コメントアウト"
 
// このスクリプトはMery Ver 3.7.2以降対応版です
// Ver 3.7.2以前の環境では動作しません
 
// -----------------------------------------------------------------------------
// 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);
 
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;
}


== 更新履歴 ==
// 挿入位置をタブと空白を考慮して決定
2019/3/4 新規作成
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;


2019/4/12 window.Quit() メソッドの使用排除
return n;
}
</syntaxhighlight>


2020/3/15 Mery 3.0.0以降対応版の追加(document.tagプロパティを使用)
=== Ver 3.0.0以降 ===
このスクリプトはMery Ver 3.0.0以降対応版です。Mery Ver 3.0.0未満の環境では、Ver 3.0.0未満対応のスクリプトを利用してください。


== コード ==
<syntaxhighlight lang="javascript" copy>
このスクリプトはMery Ver.3.0.0以降対応版です
Mery Ver.3.0.0未満の環境では、後半のスクリプトを利用してください
<syntaxhighlight lang="javascript">
#icon = "_Comment.ico"
#icon = "_Comment.ico"
#title = "選択行コメントアウト"
#title = "選択行コメントアウト"


// このスクリプトはMery Ver.3.0.0以降対応版です
// このスクリプトはMery Ver 3.0.0以降対応版です
// Ver.3.0.0以前の環境では動作しません
// Ver 3.0.0以前の環境では動作しません


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Eclipse風なコメントアウト
// Eclipse風なコメントアウト
// 複数行一括コメントアウト,復帰マクロ
// 複数行一括コメントアウト、復帰マクロ
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 2) 空白行はコメントアウトしない
// 2) 空白行はコメントアウトしない
61行目: 296行目:


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


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


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


// SHIFTキー状態を取得
// SHIFTキー状態を取得
var shift = wshShell.Run("GetKeyState.exe shift", 0, true);
var shift = wshShell.Run("GetKeyState.exe shift", 0, true);


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


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


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


 
if (comTrim != "") {
if(comTrim != ""){
var meGetLineLogical = 0;
var meGetLineLogical = 0;
var regOrg = new RegExp("^[ \\t]*" + comSelected.replace(/\W/g, "\\$&"));
var regOrg = new RegExp("^[ \\t]*" + comSelected.replace(/\W/g, "\\$&"));
143行目: 383行目:
var ed = sel.GetBottomPointY(mePosLogical);
var ed = sel.GetBottomPointY(mePosLogical);
var ac = sel.GetActivePointY(mePosLogical);
var ac = sel.GetActivePointY(mePosLogical);
if(st != ed && sel.GetBottomPointX(mePosLogical) == 1){
if (st != ed && sel.GetBottomPointX(mePosLogical) == 1) {
// 複数行選択、最下行選択位置が行頭の場合は、最終行は除外
// 複数行選択、最下行選択位置が行頭の場合は、最終行は除外
ed--;
ed--;
151行目: 391行目:
sel.SetActivePoint(mePosLogical, doc.GetLine(ed, meGetLineLogical).length + 1, ed);
sel.SetActivePoint(mePosLogical, doc.GetLine(ed, meGetLineLogical).length + 1, ed);
sel.SetAnchorPoint(mePosLogical, 1, st);
sel.SetAnchorPoint(mePosLogical, 1, st);
var lines = sel.Text.split("\n")
var lines = sel.Text.split("\n");
if(sel.Text.length > 0) sel.Untabify();
if (sel.Text.length > 0) {
sel.Untabify();
}
var linesWithoutTab = sel.Text.split("\n");
var linesWithoutTab = sel.Text.split("\n");
if(sel.Text.length > 0) doc.Undo();
if (sel.Text.length > 0) {
doc.Undo();
}


// インデント取得
// インデント取得
var indent = -1;
var indent = -1;
var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
for(var i=0, len = linesWithoutTab.length; i < len; i++){
for (var i = 0, len = linesWithoutTab.length; i < len; i++) {
var line = linesWithoutTab[i];
var line = linesWithoutTab[i];
var left = line.search(/[^ ]/);
var left = line.search(/[^ ]/);
if(left >= 0 && (indent < 0 || left < indent)){
if (left >= 0 && (indent < 0 || left < indent)) {
// インデントはタブ幅単位(左寄せ)
// インデントはタブ幅単位(左寄せ)
indent = Math.floor(left / tab) * tab;
indent = Math.floor(left / tab) * tab;
}
}
if(left >= 0){
if (left >= 0) {
// コメント行判定
// コメント行判定
if(!existNotCommentLine && line.search(regTrim) == -1){
if (!existNotCommentLine && line.search(regTrim) == -1) {
existNotCommentLine = true;
existNotCommentLine = true;
}
}
176行目: 420行目:
var txt = "";
var txt = "";
var changed = false;
var changed = false;
if(existNotCommentLine){
if (existNotCommentLine) {
// コメントアウト
// コメントアウト
for(var i = 0, len = lines.length; i < len; i++){
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i] + "\n";
var line = lines[i] + "\n";
// 空白行はコメントアウトしない
// 空白行はコメントアウトしない
if(line.search(/[^ \t\n]/) == -1){
if (line.search(/[^ \t\n]/) == -1) {
txt += line;
txt += line;
continue;
continue;
188行目: 432行目:
// 挿入位置をタブと空白を考慮して決定
// 挿入位置をタブと空白を考慮して決定
var index = 0, j;
var index = 0, j;
for(j = 0; index < indent; j++){
for (j = 0; index < indent; j++) {
// indent の範囲には半角スペースかタブしかない
// indent の範囲には半角スペースかタブしかない
if(line.charAt(j) == " "){
if (line.charAt(j) == " ") {
index += 1;
index += 1;
}else{
} else {
index += tab - (index % tab);
index += tab - (index % tab);
}
}
199行目: 443行目:
changed = true;
changed = true;
}
}
}else{
} else {
// コメントから復帰
// コメントから復帰
for(var i = 0, len = lines.length; i < len; i++){
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i] + "\n";
var line = lines[i] + "\n";
if(line.match(regTrim)){
if (line.match(regTrim)) {
if(line.match(regOrg)){
if (line.match(regOrg)) {
txt += line.replace(comSelected, ""); // 先頭のコメント(空白付き)の削除
txt += line.replace(comSelected, ""); // 先頭のコメント(空白付き)の削除
}else{
} else {
txt += line.replace(comTrim, ""); // 先頭のコメント(空白なし)の削除
txt += line.replace(comTrim, ""); // 先頭のコメント(空白なし)の削除
}
}
changed = true;
changed = true;
}else{
} else {
txt += line;
txt += line;
}
}
216行目: 460行目:
}
}


// コメントアウト部分を書き換えて,全体を選択
// コメントアウト部分を書き換えて、全体を選択
if(doc.GetLine(ed + 1, meGetLineWithNewLines) == "") txt = txt.substring(0, txt.length - 1); // 最後の改行は除去
if (doc.GetLine(ed + 1, meGetLineWithNewLines) == "") {
if(ac == st){
txt = txt.substring(0, txt.length - 1); // 最後の改行は除去
}
if (ac == st) {
// 下から上への選択状態
// 下から上への選択状態
sel.SetActivePoint(mePosLogical, 1, st);
sel.SetActivePoint(mePosLogical, 1, st);
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
if(changed) sel.Text = txt;
if (changed) {
sel.Text = txt;
}
sel.SetActivePoint(mePosLogical, 1, st);
sel.SetActivePoint(mePosLogical, 1, st);
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
}else{
} else {
// 上から下への選択状態
// 上から下への選択状態
sel.SetActivePoint(mePosLogical, 1, ed + 1);
sel.SetActivePoint(mePosLogical, 1, ed + 1);
sel.SetAnchorPoint(mePosLogical, 1, st);
sel.SetAnchorPoint(mePosLogical, 1, st);
if(changed) sel.Text = txt;
if (changed) {
sel.Text = txt;
}
sel.SetAnchorPoint(mePosLogical, 1, st);
sel.SetAnchorPoint(mePosLogical, 1, st);
}
}
240行目: 490行目:
//========================================
//========================================
// タブ幅を取得
// タブ幅を取得
function GetTabSpace()
function GetTabSpace() {
{
var doc = editor.ActiveDocument;
var doc = editor.ActiveDocument;
var sel = doc.Selection;
var sel = doc.Selection;
250行目: 499行目:
sel.Untabify();
sel.Untabify();
var n = sel.Text.length;
var n = sel.Text.length;
doc.Undo(); doc.Undo();
doc.Undo();
doc.Saved = saved
doc.Undo();
doc.Saved = saved;


return n;
return n;
}
}
</syntaxhighlight>
</syntaxhighlight>


=== Ver 3.0.0未満 ===
以下は、Mery Ver 3.0.0未満の環境でも利用できます(3.0.0以降でも動作しますが、上のバージョンの利用をお勧めします)。


以下は、Mery Ver.3.0.0未満の環境でも利用できます
<syntaxhighlight lang="javascript" copy>
(3.0.0以降でも動作しますが、上のバージョンの利用をお勧めします)
 
<syntaxhighlight lang="javascript">
#icon = "_Comment.ico"
#icon = "_Comment.ico"
#title = "選択行コメントアウト"
#title = "選択行コメントアウト"
268行目: 516行目:
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Eclipse風なコメントアウト
// Eclipse風なコメントアウト
// 複数行一括コメントアウト,復帰マクロ
// 複数行一括コメントアウト、復帰マクロ
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 1) 対象は行全体(行途中の選択も行全体とみなす)
// 2) 空白行はコメントアウトしない
// 2) 空白行はコメントアウトしない
296行目: 544行目:
var settingFilename = "_CommentMacro.ini";
var settingFilename = "_CommentMacro.ini";


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


344行目: 592行目:
// 設定ファイルからコメント文字を読み込む
// 設定ファイルからコメント文字を読み込む
var comSelected = LoadDocSetting();
var comSelected = LoadDocSetting();
if(comSelected != null){
if (comSelected != null) {
  if(comSelected == "") comSelected = COM;
if (comSelected == "") {
comSelected = COM;
}


  var comTrim = comSelected.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字
var comTrim = comSelected.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字


  // SHIFTキー状態を取得
// SHIFTキー状態を取得
  var shift = wshShell.Run("GetKeyState.exe shift", 0, true);
var shift = wshShell.Run("GetKeyState.exe shift", 0, true);


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


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


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


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();


    if(comTrim != ""){
sel.SetActivePoint(mePosLogical, doc.GetLine(ed, meGetLineLogical).length + 1, ed);
      var meGetLineLogical = 0;
sel.SetAnchorPoint(mePosLogical, 1, st);
      var regOrg = new RegExp("^[ \\t]*" + comSelected.replace(/\W/g, "\\$&"));
var lines = sel.Text.split("\n");
      var regTrim = new RegExp("^[ \\t]*" + comTrim.replace(/\W/g, "\\$&"));
if (sel.Text.length > 0) {
      var scrollY = window.ScrollY;
sel.Untabify();
      var sel = doc.Selection;
}
      var st = sel.GetTopPointY(mePosLogical);
var linesWithoutTab = sel.Text.split("\n");
      var ed = sel.GetBottomPointY(mePosLogical);
if (sel.Text.length > 0) {
      var ac = sel.GetActivePointY(mePosLogical);
doc.Undo();
      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 indent = -1;
      var lines = sel.Text.split("\n")
var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
      if(sel.Text.length > 0) sel.Untabify();
for (var i = 0, len = linesWithoutTab.length; i < len; i++) {
      var linesWithoutTab = sel.Text.split("\n");
var line = linesWithoutTab[i];
      if(sel.Text.length > 0) doc.Undo();
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 indent = -1;
var changed = false;
      var existNotCommentLine = false; // 空白・コメント行でない行が存在するか
if (existNotCommentLine) {
      for(var i=0, len = linesWithoutTab.length; i < len; i++){
// コメントアウト
        var line = linesWithoutTab[i];
for (var i = 0, len = lines.length; i < len; i++) {
        var left = line.search(/[^ ]/);
var line = lines[i] + "\n";
        if(left >= 0 && (indent < 0 || left < indent)){
// 空白行はコメントアウトしない
          // インデントはタブ幅単位(左寄せ)
if (line.search(/[^ \t\n]/) == -1) {
          indent = Math.floor(left / tab) * tab;
txt += line;
        }
continue;
        if(left >= 0){
}
          // コメント行判定
          if(!existNotCommentLine && line.search(regTrim) == -1){
            existNotCommentLine = true;
          }
        }
      }


      var txt = "";
// 挿入位置をタブと空白を考慮して決定
      var changed = false;
var index = 0, j;
      if(existNotCommentLine){
for (j = 0; index < indent; j++) {
        // コメントアウト
// indent の範囲には半角スペースかタブしかない
        for(var i = 0, len = lines.length; i < len; i++){
if (line.charAt(j) == " ") {
          var line = lines[i] + "\n";
index += 1;
          // 空白行はコメントアウトしない
} else {
          if(line.search(/[^ \t\n]/) == -1){
index += tab - (index % tab);
            txt += line;
}
            continue;
}
          }
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;
}
}
}


          // 挿入位置をタブと空白を考慮して決定
// コメントアウト部分を書き換えて、全体を選択
          var index = 0, j;
if (doc.GetLine(ed + 1, meGetLineWithNewLines) == "") {
          for(j = 0; index < indent; j++){
txt = txt.substring(0, txt.length - 1); // 最後の改行は除去
            // indent の範囲には半角スペースかタブしかない
}
            if(line.charAt(j) == " "){
if (ac == st) {
              index += 1;
// 下から上への選択状態
            }else{
sel.SetActivePoint(mePosLogical, 1, st);
              index += tab - (index % tab);
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
            }
if (changed) {
          }
sel.Text = txt;
          txt += line.substring(0, j) + comSelected + line.substring(j);
}
          changed = true;
sel.SetActivePoint(mePosLogical, 1, st);
        }
sel.SetAnchorPoint(mePosLogical, 1, ed + 1);
      }else{
} else {
        // コメントから復帰
// 上から下への選択状態
        for(var i = 0, len = lines.length; i < len; i++){
sel.SetActivePoint(mePosLogical, 1, ed + 1);
          var line = lines[i] + "\n";
sel.SetAnchorPoint(mePosLogical, 1, st);
          if(line.match(regTrim)){
if (changed) {
            if(line.match(regOrg)){
sel.Text = txt;
              txt += line.replace(comSelected, ""); // 先頭のコメント(空白付き)の削除
}
            }else{
sel.SetAnchorPoint(mePosLogical, 1, st);
              txt += line.replace(comTrim, ""); // 先頭のコメント(空白なし)の削除
}
            }
window.ScrollY = scrollY;
            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;
    }
  }
}
}


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


  return n;
return n;
}
}


// コメント文字設定をファイルから読み込み
// コメント文字設定をファイルから読み込み
function LoadDocSetting()
function LoadDocSetting() {
{
var dic = LoadDocSettingDataListWithOpend();
  var dic = LoadDocSettingDataListWithOpend();
if (dic == null) {
  if(dic == null) return null;
return null;
  var ret = "";
}
  for(var key in dic){
var ret = "";
    if(key.toLowerCase() == window.document.FullName.toLowerCase()){
for (var key in dic) {
      ret = dic[window.document.FullName.toLowerCase()];
if (key.toLowerCase() == window.document.FullName.toLowerCase()) {
    }
ret = dic[window.document.FullName.toLowerCase()];
  }
}
  return ret;
}
return ret;
}
}


// コメント文字設定をファイルに書き込み
// コメント文字設定をファイルに書き込み
function SaveDocSetting(comStr)
function SaveDocSetting(comStr) {
{
var dic = LoadDocSettingDataListWithOpend();
  var dic = LoadDocSettingDataListWithOpend();
if (dic != null) {
  if(dic != null){
dic[window.document.FullName.toLowerCase()] = comStr;
    dic[window.document.FullName.toLowerCase()] = comStr;
SaveDocSettingDataListWithOpend(dic);
    SaveDocSettingDataListWithOpend(dic);
}
  }
}
}


// 設定ファイルから全ての設定値を取得
// 設定ファイルから全ての設定値を取得
function LoadDocSettingDataListWithOpend()
function LoadDocSettingDataListWithOpend() {
{
var settingPath = GetSettingFilePath();
  var settingPath = GetSettingFilePath();
if (settingPath == "") {
  if(settingPath == "") return null;
return null;
}


  var dic = {};
var dic = {};
  var deleted = false;
var deleted = false;
  if(fso.FileExists(settingPath)){
if (fso.FileExists(settingPath)) {
    var tso = fso.OpenTextFile(settingPath, 1, false, -1);
var tso = fso.OpenTextFile(settingPath, 1, false, -1);
    while(tso.AtEndOfStream == false){
while (tso.AtEndOfStream == false) {
      var setting = tso.ReadLine().split("\t", 2);
var setting = tso.ReadLine().split("\t", 2);
      var detect = false;
var detect = false;
      for(var i = 0; i < window.Editors.Count; i++){
for (var i = 0; i < window.Editors.Count; i++) {
        for(var j = 0; j < window.Editors.Item(i).Documents.Count; j++){
for (var j = 0; j < window.Editors.Item(i).Documents.Count; j++) {
          if(window.Editors.Item(i).Documents.Item(j).FullName.toLowerCase() == setting[0].toLowerCase()){
if (window.Editors.Item(i).Documents.Item(j).FullName.toLowerCase() ==
            dic[setting[0].toLowerCase()] = setting[1];
setting[0].toLowerCase()) {
            detect = true;
dic[setting[0].toLowerCase()] = setting[1];
            break;
detect = true;
          }
break;
        }
}
        if(detect) break;
}
      }
if (detect) {
      if(detect == false) deleted = true;
break;
    }
}
    tso.Close();
}
  }
if (detect == false) {
  if(deleted) SaveDocSettingDataListWithOpend(dic);
deleted = true;
  return dic;
}
}
tso.Close();
}
if (deleted) {
SaveDocSettingDataListWithOpend(dic);
}
return dic;
}
}


// 設定ファイルを全て書き換え
// 設定ファイルを全て書き換え
function SaveDocSettingDataListWithOpend(dic)
function SaveDocSettingDataListWithOpend(dic) {
{
var settingPath = GetSettingFilePath();
  var settingPath = GetSettingFilePath();
if (settingPath != "") {
  if(settingPath != ""){
var tso = fso.OpenTextFile(settingPath, 2, true, -1);
    var tso = fso.OpenTextFile(settingPath, 2, true, -1);
for (var key in dic) {
    for(var key in dic){
tso.WriteLine(key + "\t" + dic[key]);
      tso.WriteLine(key + "\t" + dic[key]);
}
    }
tso.Close();
    tso.Close();
}
  }
}
}


// コメント文字設定ファイルの場所を取得する
// コメント文字設定ファイルの場所を取得する
function GetSettingFilePath()
function GetSettingFilePath() {
{
var meryDir = fso.GetParentFolderName(editor.FullName);
  var meryDir = fso.GetParentFolderName(editor.FullName);
var settingPath = "";
  var settingPath = "";
if (fso.FileExists(fso.BuildPath(meryDir, "Mery.ini"))) {
  if(fso.FileExists(fso.BuildPath(meryDir, "Mery.ini"))){
settingPath = fso.BuildPath(meryDir, settingFilename);
    settingPath = fso.BuildPath(meryDir, settingFilename);
} else {
  }else{
var appDataPath = fso.BuildPath(wshShell.SpecialFolders('Appdata'), 'Mery');
    var appDataPath = fso.BuildPath(wshShell.SpecialFolders('Appdata'), 'Mery');
if (fso.FileExists(fso.BuildPath(appDataPath, "Mery.ini"))) {
    if(fso.FileExists(fso.BuildPath(appDataPath, "Mery.ini"))){
settingPath = fso.BuildPath(appDataPath, settingFilename);
      settingPath = fso.BuildPath(appDataPath, settingFilename);
}
    }
}
  }
if (settingPath == "") {
  if(settingPath == ""){
window.Alert("Mery.ini ファイルが見つかりません");
    window.Alert("Mery.ini ファイルが見つかりません");
}
  }
return settingPath;
  return settingPath;
}
}
</syntaxhighlight>
</syntaxhighlight>

2025年11月26日 (水) 15:52時点における最新版

概要[編集]

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

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

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

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

注意事項[編集]

Mery Ver 3.7.2未満のソースコードでは、Shiftキーの状態を取得するために、GetKeyState.exe(キー状態取得実行ファイル)を使用しています。本体マクロと併せて上記実行ファイルも必要になります。

なお、Mery Ver 3.7.2以降のソースコードではshell.GetKeyStateメソッドを使用しているため、GetKeyState.exeは必要ありません。

変更履歴[編集]

  • 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)
    • 新規作成

ソースコード[編集]

Ver 3.7.2以降[編集]

このスクリプトはMery Ver 3.7.2以降対応版です。Mery Ver 3.7.2未満の環境では、Ver 3.0.0以降またはVer 3.0.0未満対応のスクリプトを利用してください。

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

// このスクリプトはMery Ver 3.7.2以降対応版です
// Ver 3.7.2以前の環境では動作しません

// -----------------------------------------------------------------------------
// 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);

	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;
}

Ver 3.0.0以降[編集]

このスクリプトはMery Ver 3.0.0以降対応版です。Mery Ver 3.0.0未満の環境では、Ver 3.0.0未満対応のスクリプトを利用してください。

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

// このスクリプトはMery Ver 3.0.0以降対応版です
// Ver 3.0.0以前の環境では動作しません

// -----------------------------------------------------------------------------
// 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にフォーカスがある場合に処理できない問題に対処
//
// SHIFTキー状態取得のために、"GetKeyState.exe"が必要です
//
// 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 wshShell = new ActiveXObject("WScript.Shell");

// カレントディレクトリをマクロディレクトリに変更
wshShell.CurrentDirectory = editor.FullName.match(/^.*\\/)[0] + 'Macros';

// タグ設定を取得
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 = wshShell.Run("GetKeyState.exe shift", 0, true);

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

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

		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;
}

Ver 3.0.0未満[編集]

以下は、Mery Ver 3.0.0未満の環境でも利用できます(3.0.0以降でも動作しますが、上のバージョンの利用をお勧めします)。

#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キー押下起動時はコメント文字を入力できるようにした
//    (Mery.iniと同じ場所に設定ファイルとして一時記憶)
// f) 選択方向を維持するようにした(下から上への選択対応)
// g) 空白行で実行するとUndoされてしまう問題に対処
// h) OutputBarにフォーカスがある場合に処理できない問題に対処
//
// SHIFTキー状態取得のために、"GetKeyState.exe"が必要です
//
// Improved by pizz
// -----------------------------------------------------------------------------

var doc = editor.ActiveDocument;
var COM = ""; // 単一行コメント
var settingFilename = "_CommentMacro.ini";

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 wshShell = new ActiveXObject("WScript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");

// カレントディレクトリをマクロディレクトリに変更
wshShell.CurrentDirectory = editor.FullName.match(/^.*\\/)[0] + 'Macros';

// 設定ファイルからコメント文字を読み込む
var comSelected = LoadDocSetting();
if (comSelected != null) {
	if (comSelected == "") {
		comSelected = COM;
	}

	var comTrim = comSelected.replace(/(^\s+)|(\s+$)/g, ""); // スペースなしのコメント文字

	// SHIFTキー状態を取得
	var shift = wshShell.Run("GetKeyState.exe shift", 0, true);

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

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

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

		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;
}

// コメント文字設定をファイルから読み込み
function LoadDocSetting() {
	var dic = LoadDocSettingDataListWithOpend();
	if (dic == null) {
		return null;
	}
	var ret = "";
	for (var key in dic) {
		if (key.toLowerCase() == window.document.FullName.toLowerCase()) {
			ret = dic[window.document.FullName.toLowerCase()];
		}
	}
	return ret;
}

// コメント文字設定をファイルに書き込み
function SaveDocSetting(comStr) {
	var dic = LoadDocSettingDataListWithOpend();
	if (dic != null) {
		dic[window.document.FullName.toLowerCase()] = comStr;
		SaveDocSettingDataListWithOpend(dic);
	}
}

// 設定ファイルから全ての設定値を取得
function LoadDocSettingDataListWithOpend() {
	var settingPath = GetSettingFilePath();
	if (settingPath == "") {
		return null;
	}

	var dic = {};
	var deleted = false;
	if (fso.FileExists(settingPath)) {
		var tso = fso.OpenTextFile(settingPath, 1, false, -1);
		while (tso.AtEndOfStream == false) {
			var setting = tso.ReadLine().split("\t", 2);
			var detect = false;
			for (var i = 0; i < window.Editors.Count; i++) {
				for (var j = 0; j < window.Editors.Item(i).Documents.Count; j++) {
					if (window.Editors.Item(i).Documents.Item(j).FullName.toLowerCase() ==
						setting[0].toLowerCase()) {
						dic[setting[0].toLowerCase()] = setting[1];
						detect = true;
						break;
					}
				}
				if (detect) {
					break;
				}
			}
			if (detect == false) {
				deleted = true;
			}
		}
		tso.Close();
	}
	if (deleted) {
		SaveDocSettingDataListWithOpend(dic);
	}
	return dic;
}

// 設定ファイルを全て書き換え
function SaveDocSettingDataListWithOpend(dic) {
	var settingPath = GetSettingFilePath();
	if (settingPath != "") {
		var tso = fso.OpenTextFile(settingPath, 2, true, -1);
		for (var key in dic) {
			tso.WriteLine(key + "\t" + dic[key]);
		}
		tso.Close();
	}
}

// コメント文字設定ファイルの場所を取得する
function GetSettingFilePath() {
	var meryDir = fso.GetParentFolderName(editor.FullName);
	var settingPath = "";
	if (fso.FileExists(fso.BuildPath(meryDir, "Mery.ini"))) {
		settingPath = fso.BuildPath(meryDir, settingFilename);
	} else {
		var appDataPath = fso.BuildPath(wshShell.SpecialFolders('Appdata'), 'Mery');
		if (fso.FileExists(fso.BuildPath(appDataPath, "Mery.ini"))) {
			settingPath = fso.BuildPath(appDataPath, settingFilename);
		}
	}
	if (settingPath == "") {
		window.Alert("Mery.ini ファイルが見つかりません");
	}
	return settingPath;
}
スポンサーリンク