「引用符/コメント」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
MSY-07 (トーク | 投稿記録)
改行の修正、空行の除去
 
(2人の利用者による、間の9版が非表示)
1行目: 1行目:
<div style="float:right">__TOC__</div>
<div style="float:right">
__TOC__
 
画像は 2019/04/07 版のものです。
 
2020/06/23 版では、サブメニューに削除系コマンドをまとめてあります。
</div>
[[ファイル:引用符/コメント_ポップアップメニュー.png|link=]]
[[ファイル:引用符/コメント_ポップアップメニュー.png|link=]]


== 引用符/コメント ==
== 引用符/コメント ==
'''引用の追加'''」マクロのコードを改変しました。
Kuro 氏の「'''引用の追加'''」マクロのコードを改変しました。
 
* ポップアップメニューから任意の '''引用マーク''' や '''箇条書きの行頭記号'''、'''行コメントの記号''' などの種類を選択して、選択範囲内の各行頭に追加します。<br> 選択範囲がないばあいはカーソル行の先頭に挿入します。


* ポップアップメニューから任意の '''引用マーク''' や '''箇条書きの行頭記号'''、'''行コメントの記号''' などの種類を選択して、選択範囲をふくむの各行の先頭に追加します。選択範囲がないばあいはカーソル行の先頭に挿入します。
* 行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで末尾改行が含まれているばあい、さいごの改行を無視します。
* 行頭に挿入する文字列として '''クリップボード''' の文字列データや '''入力ダイアログ''' で指定した文字列を使用することもできます。
* 行頭に挿入する文字列として '''クリップボード''' の文字列データや '''入力ダイアログ''' で指定した文字列を使用することもできます。
 
・「クリップボード」の機能は「[[行の先頭に貼り付け]]」マクロとおなじものです。
* ルーラーの行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで末尾改行が含まれているばあい、さいごの改行を無視します。
・「任意の文字列」は改行コードやタブ文字も記述できますが、それぞれ入力ダイアログで「'''\\\n'''」と「'''\\\t'''」で入力されたもの (注:¥記号3つ) を改行コードとタブ文字に置換するようにしてあります。
※「\n」や「\t」と記述したばあい、そのままの文字列として「\n」や「\t」が返されます。


== 挿入/削除できる引用マークやコメントマーク ==
== 挿入/削除できる引用マークやコメントマーク ==
* 各行の先頭にメタ記号を追加
* 各行の先頭にメタ記号を追加
: ポップアップメニュー内に表示するラベル(注釈)や並び順をカスタマイズすると、Markdown 用のマークアップなどに活用しやすくなります。
: 以下は、公開・配布しているソースコードの初期状態で利用できる引用マークやコメントマークです。
:* '''␣''' がついたものは、半角スペースつきで記号を挿入します。
:* '''␣''' がついたものは、半角スペースつきで記号を挿入します。
:*「1つ削除」/「すべて削除」では、記号のうしろの半角スペースの有無を区別しません。
:*「1つ削除」/「すべて削除」では、記号のうしろの半角スペースの有無を区別しません。
24行目: 32行目:
  '''・''' (箇条書き 全角中黒)
  '''・''' (箇条書き 全角中黒)
  ␣ '''*''' ␣ (箇条書き アスタリスク)
  ␣ '''*''' ␣ (箇条書き アスタリスク)
'''*''' ␣ (箇条書き アスタリスク)
  '''-''' ␣ (箇条書き 半角ハイフンマイナス)
  '''-''' ␣ (箇条書き 半角ハイフンマイナス)
  '''※''' (注意書き ※印)
  '''※''' (注意書き ※印)
30行目: 39行目:
  ☐ (全角スペース)
  ☐ (全角スペース)
  › (TABコード)
  › (TABコード)
⏎ (空行: 改行コード) ※削除コマンドからの削除不可
   
   
  '''//''' ␣ (C系, JavaScript コメント)
  '''//''' ␣ (C系, JavaScript コメント)
40行目: 50行目:
  '''REM''' ␣ (BAT コメント)
  '''REM''' ␣ (BAT コメント)


: ※以下の3種は、「1つ削除」/「すべて削除」ではアンコメントされません。ポップアップメニュー内にそれぞれ専用の "アンコメント" コマンドがあります)


※以下の3種は、「1つ削除」/「すべて削除」ではアンコメントされません。
* 選択範囲の行全体をひとまとめでコメントアウト
 
* 選択範囲の行全体をひとつのコメントとしてコメントアウト
  '''<nowiki><!--</nowiki>''' (XML コメント) '''-->'''
  '''<nowiki><!--</nowiki>''' (XML コメント) '''-->'''
  '''/*''' (C系, JavaScript コメント) '''*/'''
  '''/*''' (C系, JavaScript コメント) '''*/'''


* 選択範囲の行全体を複数行形式でコメントアウト
* 選択範囲の行全体を'''複数行'''形式でコメントアウト(※字下げ位置でコメントアウトします)


  '''/*'''
  '''/*'''
  ''' * ''' (C系, JavaScript コメント)
  ''' * ''' (C系, JavaScript ブロックコメント)
  ''' */'''
  ''' */'''


: ポップアップメニューの既存の項目を減らしたいばあいは、ソースコード内の "m.Add( … );" の行を // でコメントアウトするとその項目をメニューから隠せます。<br>ただし、メニューから隠れるだけで、「1つ削除」/「すべて削除」の対象から除外されるわけではありません。
; 削除系コマンド
 
* '''1つ削除'''
: 選択範囲内の各行の行頭から、設定項目の「引用符の種類」に登録されている記号や文字列と一致するものを1つずつ削除します (※ 改行記号 <code>"\n"</code> は対象外 ⇒ 「空行を削除」コマンド)。
* '''すべて削除'''
: 選択範囲内の各行の行頭から、設定項目の「引用符の種類」に登録されている記号や文字列と一致するものをすべて削除します (※ 改行記号 <code>"\n"</code> は対象外)。
* '''空行を削除'''
: 選択範囲内の空行を削除します。
* '''行頭の空白文字を削除'''
: 選択範囲内の各行の行頭から、全角/半角空白とタブ文字をすべて削除します。
: ※ このマクロでは、行末の空白文字列の削除はできません ( ⇒ 「[[カッコで囲う]]」マクロや「[[テキスト整形]]」マクロを利用してください)。
* '''行頭から任意の文字列を削除'''
: 選択範囲内の各行の行頭から、入力ダイアログで指定された文字列を削除します。
* '''行頭から任意の文字数を削除'''
: 選択範囲内の各行の行頭から、入力ダイアログで指定された文字数だけ削除します。
: ポップアップメニューの既存の項目を減らしたいばあいは、ソースコード内の "m.Add( … );" の行を // でコメントアウトするとその項目をメニューから隠せます。ただし、メニューから隠れるだけで、「1つ削除」/「すべて削除」の対象から除外されるわけではありません。


== ダウンロード ==
== ダウンロード ==
ダウンロード: 「[[メディア:引用符/コメントマーク.zip|引用符/コメントマーク.zip]]」(アイコン入り)
ダウンロード: 「[[ファイル:引用符/コメント.zip]]」(アイコン入り)
* 第四版: 2020/06/23
: コマンドを追加: 「任意の文字数を削除」
: マルチカーソル/複数選択範囲に対応
* 第三版: 2019/04/07
: コマンドを追加: 「空行の追加」、「任意の文字列を削除」
* 第二版: 2018/10/30
* 第一版: 2018/10/28


== ソースコード ==
== ソースコード ==
<source lang="javascript">
<syntaxhighlight lang="javascript" style="height:120em; overflow:auto;">
#title = "引用符を追加..."
#title = "引用符を追加..."
#tooltip = "引用符/コメントマークを追加・削除"
#tooltip = "引用符/コメントマークを追加・削除"
#icon = "quote2[3].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",96
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",96


// 選択範囲の行頭に引用符/コメントマークを追加・削除する
/**
// 公式wikiのマクロライブラリの「引用の追加」を改造した
  * -----------------------------------------------------------------------------
// (Last modified: 2018/10/28)
 
/*
  * --------------------------------------------------
  * 引用の追加 ( => 2018/10/14 公開停止)
  * 引用の追加 ( => 2018/10/14 公開停止)
  * Orginal Copyright (c) Kuro. All Rights Reserved.
  * Orginal Copyright (c) Kuro. All Rights Reserved.
  * www:    http://www.haijin-boys.com/
  * www:    http://www.haijin-boys.com/
  * --------------------------------------------------
  * -----------------------------------------------------------------------------
  * Modified by sukemaru
  * Modified by sukemaru (2018/10/28 - 2020/06/23)
  * 「引用符を追加」または「引用符/コメント」
  * 「引用符を追加」または「引用符/コメント」
  * --------------------------------------------------
  * 選択範囲の行頭に引用符/コメントマークを追加・削除する
  * Kuro 版からの変更点
* -----------------------------------------------------------------------------
  * Kuro 版「引用の追加」マクロからの変更点 ▼
  *  
  *  
  * ・ポップアップメニューの体裁を変更した。
  * ・ポップアップメニューの体裁を変更した。
  * ・引用符の種類を増やした(※ 基本的に「メタ文字+半角スペース」)。
  * ・引用符の種類を増やした(※ 基本的に「メタ文字+半角スペース」)。
  * ・「クリップボード」と「任意の文字列」を追加。
  * ・「クリップボード」と「任意の文字列」を追加。
  * ・配列に削除用の要素(半角スペースなしのメタ文字のみ差分)も余分に追加した。
  * ・配列に削除用の要素(半角スペースなしのメタ文字のみの差分)も余分に追加した。
  *  ※「すべて削除」では、半角スペース、全角スペース、タブ文字での字下げをすべて削除する。
  *  ※「すべて削除」では、半角スペース、全角スペース、タブ文字での字下げをすべて削除する。
  *  ※「クリップボード」、「任意の文字列」、「JS/XML コメントアウト」は、「1つ削除//すべて削除」では削除できない。
  *  ※「クリップボード」、「任意の文字列」、「空行」、「JS/XML コメントアウト」は、
*    「1つ削除//すべて削除」では削除されない。
  *  
  *  
  * ・選択範囲があったときには行全体に拡張・復帰するコードにした。
  * ・選択範囲があったときには行全体に拡張・復帰するようにした。
  * ・選択範囲なしの状態からカーソル行にたいして「追加/1つ削除/すべて削除」を実行したときは、
  * ・選択範囲なしの状態からカーソル行にたいして「追加/1つ削除/すべて削除」を実行したときは、
  *  実行前の位置にカーソルを返せるようにした(undo すると行全体が選択範囲になってしまうのはマクロの仕様)。
  *  実行前の位置にカーソルを返せるようにした。
  * ・「1つ削除」の不具合箇所を修正した。
  * ・「1つ削除」の不具合箇所を修正した。
*
* ※ 「任意の文字列」について ※
* ・文字コードでの入力には非対応(入力されたままの文字列を返す)。
* ・改行コードとタブ文字は、それぞれ「\\\n」と「\\\t」で入力されたものを「\n」と「\t」に置換する。
*  パスの入力に配慮しただけの簡易的な置換処理なので、「\」を4つ以上かさねた場合を考慮していない。
*
* ※ 「JS コメントアウト」と「JS アンコメント」について ※
* ・「引用の追加」では選択範囲を拡張してコメントアウトするので、
*  行の中間部分だけをコメントアウトするなら「カッコで囲う」マクロが適する。
* ・JSアンコメントはコメント文の行頭記号を消してしまうので要注意。
*  基本的にこのマクロでつけられた、「中間行にアスタリスクを打った JS コメント」しか考慮していない。
* ・ほかにも注意事項があるので、該当コード部分の注意書きを参照のこと!
*
* ポップアップメニューの項目は、m.Add( … ); の不要な行をコメントアウトすれば隠すことができる。
*  ただし、メニューから隠しても、配列 q にある要素は「1つ削除/すべて削除」の対象になる。
* (配列から削除する場合は "" の中身だけを消すこと。
*  "" として空要素を残しておかないと、メニューや処理コードの ID と一致しなくなる)
  */
  */


// 引用符の種類
// ---------- ▼ 設定項目 ▼ ---------- //
var q = new Array( "" , // 以下 r = 1~10、11~20、21~30、31~ の ID 順
 
// ■ 「任意の文字列」で入力した文字列の一時記憶方法
var tagType = 2;
  // 0 : 一時記憶なし
  // 1 : タブ(文書)ごとに一時記憶する(Document.Tag)
  // 2 : ウインドウごとに一時記憶する(Editor.Tag)
  // 3 : すべてのタブとウインドウ共通で一時記憶する(window.Tag)
 
 
// ■ 引用符の種類(追加用)
var q = [ "" , // 以下 r = 1~10、11~20、21~30、31~ の ID 順
   "> " ,  "・" ,  " * " ,  "- " ,  " " ,  " " ,  "\t" ,  "// " ,  "# " ,  "; " ,
   "> " ,  "・" ,  " * " ,  "- " ,  " " ,  " " ,  "\t" ,  "// " ,  "# " ,  "; " ,
   "' " ,  "-- " ,  ": " ,  ":: " ,  "REM " ,  "※" ,  "" ,  "" ,  ">> " ,  ">>" ,
   "' " ,  "-- " ,  ": " ,  ":: " ,  "REM " ,  "※" ,  ">>" ,  "* " ,  "" ,  "" ,
   ">" ,  "" ,  "" ,  "· " ,  "·" ,  "* " ,  "*" ,  "--" ,  "-" ,  "//" ,
   "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,
   "#" ,  ";" ,  "'" ,  "::" ,  ":" );
   "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,
  // ※半角スペースの有無で「1つ削除/すべて削除」がマッチしなくなるので、
"" ];
   //  ">> " 以降に半角スペース あり/なし の差分要素を適当に追加してある。
 
  // ※半角スペース差分(中黒=ビュレットは全角/半角差分も)の変更は、配列内の編集ではなく
 
   //  ポップアップメニュー項目のID(番号)変更で対応しないと、「1つ削除/すべて削除」が効かなくなる。
/*
  // (同一文字をふくむ要素は文字列の長いものが先に置かれていないとダメ)。
* ※半角スペースの有無で「1つ削除/すべて削除」がマッチしなくなるので、
  // 「・」は半角カナの中黒(U+FF65)、「·」は欧文用ユニコード文字のビュレット(U+00B7)
*   以下に半角スペース あり/なし の差分要素を適当に追加してあります。
* ※半角スペース差分(中黒=ビュレットは全角/半角差分も)の変更は、配列内の編集ではなく
*   ポップアップメニュー項目のID(番号)変更で対応しないと、「1つ削除/すべて削除」が効かなくなります
* (同一文字をふくむ要素は文字列の長いものが先に置かれていないとダメ)。
* 「・」は半角カナの中黒(U+FF65)、「·」は欧文用ユニコード文字のビュレット(U+00B7)
*/
// ■ 引用符の種類(削除用差分)
var qq = [
  ">" ,  "・ " ,  "・" ,  "· " ,  "·" ,  "*" ,  "-" ,  "//" ,  "#" ,  ";" ,
  "'" ,  "--" ,  ":" ,  "::" ,  "" ,  "" ,  ""
];
q = q.concat( qq );


// ---------- ▲ 設定項目 ▲ ---------- //


// ポップアップメニューの項目とID
var d = editor.ActiveDocument;
var s = editor.ActiveDocument.selection;
var m = CreatePopupMenu();
var m = CreatePopupMenu();
if ( d.ReadOnly ) {
  m.Add( " ドキュメントは 書き換え禁止 です & ", 0 );
}
else {
  var cb = ClipboardData.GetData(); // クリップボードのテキストデータを取得
  // ポップアップメニューの項目とID
   // m.Add( "ラベル", r ); の各行は、任意に上下移動(並べ替え)してよいが、
   // m.Add( "ラベル", r ); の各行は、任意に上下移動(並べ替え)してよいが、
   // r の数値は上の配列 q の並び順やテキスト変換処理の case r: に対応しているので変更しないこと!
   // r の数値は上の配列 q の並び順やテキスト変換処理の case r: に対応しているので変更しないこと!


m.Add( " 任意の文字列 (&E)", 50 );
  m.Add( "任意の文字列 (&E)...", 1010 );
m.Add( " クリップボード (&C)", 40 );
  m.Add( "[ … ] クリップボード (&C)", 1000, !cb *2 );
m.Add( "", 0, meMenuSeparator );
 
m.Add( "> > メール引用符 (&>)", 1 );
  m.Add( "", 0, meMenuSeparator );
m.Add( ">> >> BBS アンカー (&>)", 20 );
  m.AddPopup( "▲ 削除 (&D)", sm1 = CreatePopupMenu() );
m.Add( "・ ・ 箇条書き (&/)", 2 );
    sm1.Add( "● 1つ削除 (&D)", 1013 );
m.Add( " * * 箇条書き (&*)", 3 );
    sm1.Add( "● すべて削除 (&A)", 1014 );
m.Add( "- - 箇条書き (&-)", 4 );
    sm1.Add( "", 0, meMenuSeparator );
m.Add( "※ ※注意書き (&K)", 16 );
    sm1.Add( " ↲ 空行を削除 (&B)", 1015 );
m.Add( "", 0, meMenuSeparator );
    sm1.Add( "␣␣ 行頭の空白文字を削除 (&S)", 1016 );
m.Add( "␣ 半角スペース (&1)", 5 );
    sm1.Add( "", 0, meMenuSeparator );
m.Add( "⃞ 全角スペース (&2)", 6 );
    sm1.Add( "? 行頭から任意の文字列を削除 (&Q)...", 1011 );
m.Add( "› タブコード (&T)", 7 );
    sm1.Add( "? 行頭から任意の文字数を削除 (&X)...", 1012 );
m.Add( "", 0, meMenuSeparator );
 
m.Add( "\/\/ JS・C コメント (&J)", 8 );
  m.Add( "", 0, meMenuSeparator );
m.Add( "# Perl コメント (&P)", 9 );
  m.Add( "> > メール引用符 (&>)", 1 );
m.Add( "; INI コメント (&I)", 10 );
  m.Add( ">> >> BBS アンカー (&>)", 17 );
m.Add( "’ VB コメント (&V)", 11 );
  m.Add( "・ ・ 箇条書き (&/)", 2 );
m.Add( "-- SQL コメント (&S)", 12 );
  m.Add( " * * 箇条書き (&*)", 3 );
m.Add( ": MS-DOS ラベル (&M)", 13 );
  m.Add( "* * 箇条書き (&W)", 18 );
m.Add( ":: BAT コメント (&B)", 14 );
  m.Add( "- - 箇条書き (&-)", 4 );
m.Add( "REM BAT コメント (&R)", 15 );
  m.Add( "※ ※注意書き (&K)", 16 );
m.Add( "", 0, meMenuSeparator );
 
m.Add( " 1つ削除 (&D)", 17 );
  m.Add( "", 0, meMenuSeparator );
m.Add( " すべて削除 (&A)", 18 );
  m.Add( "␣ 半角スペース (&1)", 5 );
m.Add( "", 0, meMenuSeparator );
  m.Add( "⃞ 全角スペース (&2)", 6 );
m.Add( "/*  *  */ JS コメントアウト 2 (&J)", 42 );
  m.Add( "› タブコード (&T)", 7 );
m.Add( "/*  */ JS コメントアウト 1  (&J)", 41 );
  m.Add( "⏎ 空行 (&N) ...", 1006 );
m.Add( " JS アンコメント (&U)", 43 );
 
m.Add( "", 0, meMenuSeparator );
  m.Add( "", 0, meMenuSeparator );
m.Add( "<!--  --> XML コメントアウト (&X)", 44 );
  m.Add( "\/\/ JS・C コメント (&J)", 8 ); // アクセラレータは「JS コメントアウト」と重複
m.Add( " XML アンコメント (&L)", 45 );
  m.Add( "# Perl コメント (&P)", 9 );
// m.Add( "", 0, meMenuSeparator );
  m.Add( "; INI コメント (&I)", 10 );
// m.Add( "キャンセル", 0 ); // Escキーでキャンセルできるのでアクセラレータなし
  m.Add( "’ VB コメント (&V)", 11 );
  m.Add( "-- SQL コメント (&S)", 12 );
  m.Add( ": MS-DOS ラベル (&M)", 13 );
  m.Add( ":: BAT コメント (&B)", 14 );
  m.Add( "REM BAT コメント (&R)", 15 );
 
  m.Add( "", 0, meMenuSeparator );
  m.Add( "/*  *  */ JS コメントアウト 2 (&J)", 1002 );
  m.Add( "/*  */ JS コメントアウト 1  (&J)", 1001 );
  m.Add( " JS アンコメント (&U)", 1003 );
  m.Add( "", 0, meMenuSeparator );
  m.Add( "<!--  --> XML コメントアウト (&X)", 1004 );
  m.Add( " XML アンコメント (&L)", 1005 );
 
  m.Add( "", 0, meMenuSeparator );
  m.Add( "キャンセル & ", 0 );
}


// ポップアップメニューの表示
// ポップアップメニューの表示
169行目: 229行目:


if ( r > 0 ) {
if ( r > 0 ) {
   Redraw = false;
   var p;
   var sx = ScrollX, sy = ScrollY; // スクロール位置を保存
  var tagKey = "LineCommentQuote";
   var s = document.selection;
  if ( r === 1010 ) { p = AddStrPrompt( tagType, tagKey ); }
    
  if ( r === 1011 ) { p = DelStrPrompt( tagType, tagKey ); }
   // 選択範囲がないときのカーソル位置を取得
  if ( r === 1012 ) { p = DelByNumPrompt(); } // 「任意の文字数を削除」
   if ( s.IsEmpty )
 
    var pos = s.GetActivePos();
   var sx = ScrollX, sy = ScrollY;
  // 選択範囲を取得する
  // マルチカーソル対応
   var ax = s.GetTopPointX( mePosLogical );
   var arg = [ q, r, p, cb ];
   var ay = s.GetTopPointY( mePosLogical );
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! s.Mode || s.Mode === meModeStream ) {
    LineCommentQuote_Main( arg );
   }
   // 矩形選択または複数選択のとき
  else {
    BeginUndoGroup();
    AddUndo();
    MultiFunction( LineCommentQuote_Main, arg );
    EndUndoGroup();
  }
   ScrollX = sx;  ScrollY = sy;
}
 
 
/**
* 関数 LineCommentQuote_Main( [ q, r, p, cb ] )
* 「引用符/コメント」マクロ
*/
function LineCommentQuote_Main( arg ) {
  var q  = arg[0];
  var r  = arg[1];
  var p  = arg[2];
  var cb = arg[3];
 
  // 選択範囲
  var d = editor.ActiveDocument;
  var s = editor.ActiveDocument.selection;
  var pos = s.IsEmpty ? s.GetActivePos() : -1;
   var tx = s.GetTopPointX( mePosLogical );
   var ty = s.GetTopPointY( mePosLogical );
   var bx = s.GetBottomPointX( mePosLogical );
   var bx = s.GetBottomPointX( mePosLogical );
   var by = s.GetBottomPointY( mePosLogical );
   var by = s.GetBottomPointY( mePosLogical );
   // 選択範囲の末尾が行頭にあるときの調整
   // 選択範囲の末尾が行頭にあるときの調整
   if ( ay != by && bx == 1 && document.Text.charAt( s.GetActivePos() ) )
   if ( ty < by && bx == 1 && d.Text.charAt( s.GetActivePos() ) ) {
     by --;
     by --;
   // 選択範囲を拡張して確定する
  }
   // 選択範囲を拡張
   s.SetActivePoint( mePosLogical, 1, by );
   s.SetActivePoint( mePosLogical, 1, by );
   s.EndOfLine( false, mePosLogical );
   s.EndOfLine( false, mePosLogical );
   s.SetAnchorPoint( mePosLogical, 1, ay );
   s.SetAnchorPoint( mePosLogical, 1, ty );


   // 選択範囲の文字列を取得
   // 選択範囲の文字列を取得
   var st = document.selection.Text; // 拡張された行全体のテキスト
   var st = tmp = s.Text;
  var exit = false; // Quit の代用フラグ


   // IDごとのテキスト変換処理
   // IDごとのテキスト変換処理
   switch ( r ) {
   switch ( r ) {


    case 1:  case 2:  case 3:  case 4:  case 5: case 6:  case 7:  case 8:  case 9:  case 10:  
  // 引用符/コメントマークを追加
    case 11:  case 12:  case 13:  case 14:  case 15:  case 16:  case 20:
  case 1:  case 2:  case 3:  case 4:  case 5:
      // 引用符を追加
  case 6:  case 7:  case 8:  case 9:  case 10:  
      s.Text = insertQuote( st, q[r] );
  case 11:  case 12:  case 13:  case 14:  case 15:
  case 16:  case 17:  case 18:
    // 各行の先頭に引用符/コメントマークを追加
    s.Text = st.replace( /^/gm, q[r] );
//    /* とりあえずコメントアウトしておく */
//    // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
//    if ( pos > -1 ) {
//      s.SetActivePos( pos + q[r].length );
//      exit = true;
//    }
    break;
 
  // クリップボード
  case 1000:
    s.Text = st.replace( /^/gm, cb );
    if ( pos > -1 ) { s.SetActivePos( pos + cb.length );  exit = true; }
    break;


      /* とりあえずコメントアウトしておく */  
  // 空行を挿入 ※空行は削除コマンドの削除対象に含まれない
//       // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
  case 1006:
//      if ( pos ) { s.SetActivePos( pos + q[r].length );  Quit(); }
    var n = "\n"; // 空改行
      break;
    s.Text = st.replace( /^/gm, n );
    if ( pos > -1 ) { s.SetActivePos( pos + n.length );  exit = true; }
    break;


  // 任意の文字列(テキストボックス)
  case 1010:
    if ( p ) { s.Text = st.replace( /^/gm, p ); }
    if ( pos > -1 ) { s.SetActivePos( pos + p.length );  exit = true; }
    break;


    case 17:
 
       // 各行の先頭の引用符/コメントマークを1つ削除
  // 任意の文字列を削除
      var dt = deleteQuote( st );
  case 1011:
      // 選択範囲に引用符/コメントマークがなかった場合 undo 履歴を残さない
    var reg = new RegExp(
      if ( dt == st ) {
       "^" + p.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" )
        if ( pos ) { s.SetActivePos( pos );  Quit(); }
    , "gm" );
         break;
    tmp = st.replace( reg, "" );
    if ( tmp !== st ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length ) {
        s.SetActivePos( pos - ( st.length - tmp.length ) );
         exit = true;
       }
       }
      // 1つ削除完了
    }
      s.Text = dt;
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;


      // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
  // 任意の文字数を削除
       if ( pos && dt.length ) {
  case 1012:
        s.SetActivePos( pos - ( st.length - dt.length ) );
    if ( p && st ) {
         Quit();
      tmp = DeleteCharByNum( st, p );
       if ( tmp !== st ) {
        s.Text = tmp;
        if ( pos > -1 && tmp.length ) {
          s.SetActivePos( pos - ( st.length - tmp.length ) );
          exit = true;
         }
       }
       }
       break;
       else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    }
    break


  // 1つ削除
  case 1013:
    // 各行ごとに、配列 q の並び順で最初にマッチした引用符/コメントマークを削除
    tmp = DeleteQuote( st, q );
    if ( tmp !== st ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length ) {
        s.SetActivePos( pos - ( st.length - tmp.length ) );
        exit = true;
      }
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;


    case 18:
  // すべて削除
      var org = st;
  case 1014:
      // 各行の先頭の引用符/コメントマークをすべて削除
    var org = st; // DeleteQuote() のループ処理前のテキスト
      for ( var i = 0; i < 40; i ++ ) { // st を最大40回 deleteQuote() でループ処理
    // st を最大40回 DeleteQuote() でループ処理
        var dt = deleteQuote( st );
    for ( var i = 0; i < 40; i ++ ) {
        if ( dt == st ) break;
      tmp = DeleteQuote( st, q );
         else  st = dt;
      // DeleteQuote() 処理の前後でテキストが一致したらループを抜ける
      if ( tmp == st ) { break; }
      st = tmp; // DeleteQuote() したテキスト tmp を st に再代入
    }
    if ( tmp !== org ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length) {
        s.SetActivePos( pos - ( org.length - tmp.length ) );
         exit = true;
       }
       }
      // 選択範囲に引用符/コメントマークがなかった場合 undo 履歴を残さない
    }
      if ( dt == org ) {
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
        if ( pos ) { s.SetActivePos( pos );  Quit(); }
    break;
        break;
 
       }
  // 空行を削除
       // すべて削除完了
  case 1015:
       s.Text = dt;
    // キャレット位置が空行上のとき
    if ( pos > -1 && tx == 1 && d.GetLine( ty, 0 ) == "" ) {
       s.Delete();  exit = true;
    }
    else {
       tmp = st.replace( /\n+/g, "\n" );
       if ( st !== tmp ) { s.Text = tmp; }
      else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    }
    break;


      // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
  // 行頭の空白文字を削除
       if ( pos && dt.length) {
  case 1016:
         s.SetActivePos( pos - ( org.length - dt.length ) );
    tmp = st.replace( /^[\t  ]+/gm, "" );
         Quit();
    if ( tmp !== st ) {
      s.Text = tmp;
       if ( pos > -1 && tmp.length ) {
         s.SetActivePos( pos - ( st.length - tmp.length ) );
         exit = true;
       }
       }
      break;
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;




    case 40:
  /* JavaScript コメントアウト1 */
      // クリップボードのテキストデータを取得して、各行の先頭に追加
  // <!-- XML コメントアウト --> 
      var cb = ClipboardData.GetData();
  case 1001:  case 1004:
      if ( cb )
    // 「引用の追加」では行単位に拡張した選択範囲をまとめてコメントアウトするので、
        s.Text = insertQuote( st, cb );
    // 行の中間部分だけをコメントアウトするなら「カッコで囲う」マクロを使うこと。
    var p1 = ( r == 1001 ) ? "/\* " : "<!-- ";
    var p2 = ( r == 1001 ) ? " */"  : " -->";
    s.Text = p1 + st + p2;
    if ( ! st ) {
      s.SetActivePos( pos + p1.length );  exit = true;
    }
    break;


      // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
  /* * JavaScript コメントアウト2 */
      if ( pos ) { s.SetActivePos( pos + cb.length ); Quit(); }
  case 1002:
      break;
    var p1 = "/\**",  p2 = " */",  ast = " * ",  n = "\n";
    s.Text = CommentOutJS( st, p1, p2, ast );
    // マクロ実行前に空行だった場合はカーソルをコメント枠のなかに移動
    if ( pos > -1 ) {
      s.SetActivePos( pos + ( p1 + n + ast ).length );
      exit = true;
    }
    // カーソルを接頭辞のうしろに移動
    else {
      s.SetActivePoint( mePosLogical, 1, ty );
      s.EndOfLine(); exit = true;
    }
    break;


  /* JSアンコメント */ // ※選択範囲内の各行頭のコメントマークにのみマッチ
  // case 41 & 42 の JavaScript コメント をアンコメントする
  case 1003:
    // コメントの "接頭辞" と "接尾辞" と "行頭記号" を正規表現で配列に
    var p = new Array( "\\/\\*+ ?" , " ?\\*\\/" , " ?(\\*|[・・]) ?" );
    tmp = DeleteComment( st, p )
    if ( tmp !== st ) { s.Text = tmp; } // アンコメント完了
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;


    case 50:
  /* XML アンコメント */
      // ※文字コードには非対応(テキストボックスに入力されたままの文字列を返す)
  // case 44 の <!--␣ XMLコメント ␣--> をアンコメントする
      // ダイアログのテキスト入力フィールドから文字列を取得して、各行の先頭に追加
  case 1005:
      var p = Prompt(
    tmp = st.replace( / ?<!-+ ?| ?-+ *> ?/g , "" );
        "前につける文字列:\t改行=\\\\\\n ; タブ=\\\\\\t  (注:¥記号3つ)", ""
    if ( tmp !== st ) { s.Text = tmp; }
      ).replace( /\\\\\\n/g , "\n" ).replace( /\\\\\\t/g , "\t" );
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
      if ( p )
    break;
        s.Text = insertQuote( st, p );


      // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
  default:
      if ( pos ) { s.SetActivePos( pos + p.length );  Quit(); }
    break;
      break;
  } // end switch(r)


    case 41:  case 44:
  // 選択範囲を復元
      // 「引用の追加」では行単位に拡張した選択範囲をまとめてコメントアウトするので、
  if ( ! exit ) {
      // 行の中間部分だけをコメントアウトするなら「カッコで囲う」マクロを使うこと。
    // ※移動/コピー/切り取り しやすいように末尾改行まで含める
      var p1, p2;
    s.SetActivePos( s.GetActivePos() + 1 );
      if ( r == 41 ) { p1 = "/* ";  p2 = " */"; } // /* JavaScript コメントアウト1 */
    s.SetAnchorPoint( mePosLogical, 1, ty );
      else { p1 = "<!-- ",  p2 = " -->"; } // ( r == 44 ) // <!-- XML コメントアウト -->
      // 空行のばあい、コメントマーク p1 & p2 だけ挿入して、カーソルをコメント枠のなかに移動
      if ( pos ){
        document.Write( p1 + p2 );
        s.SetActivePos( pos + p1.length );
        Quit();
      }
      // 空行以外のばあい、選択範囲 st をコメントアウト
      s.Text = p1 + st + p2;


      /* とりあえずコメントアウトしておく */  
    // 選択範囲の中身が \n のみなら選択解除
//       // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
    if ( /^\n$/.test( s.Text ) ) {
//      if ( pos && dt.length) { s.SetActivePos( pos + p1.length );  Quit(); }
      s.SetActivePos( s.GetAnchorPos() );
      break;
    }
  }
}




    case 42:
/* 関数 DeleteQuote( str, q ) */
      /*  
function DeleteQuote( str, q ) {
      * ・先頭行の字下げを基準に2行目以降も字下げするが、
   var a = str.split( "\n" );
      *   先頭行より字下げ量が少ない行はレイアウトが崩れる(「アンコメント」するとさらに崩れる)。
  for ( var i = 0, len = a.length; i < len; i ++ ) {
      * ・先頭に最少量の字下げする空白行を置くとレイアウトを維持でき、
    for ( var j = 0, qLen = q.length, qt; j < qLen; j ++ ) {
      *  「アンコメント」してもレイアウトを保持できる。
       qt = q[j];
      */
       if ( ! qt ) { continue; }
      var p1 = "/* ", p2 = " */", ast = " * ", n = "\n";
      if ( a[i].substr( 0, qt.length ) === qt ) {
       // 空行のばあい、コメントマーク /* \n & * & \n */ だけ挿入して、カーソルをコメント枠のなかに移動
         a[i] = a[i].substr( qt.length );
       if ( pos ){
         break;
        s.Text = p1 + n + ast + n + p2;
         s.SetActivePos( pos + ( p1 + n + ast ).length );
         Quit();
       }
       }
      // 空行以外のばあい、選択範囲全体を /* *コメントアウト */
    }
      s.Text = CommentOutJS( st, p1, p2, ast );
  }
      break;
  return a.join( "\n" );
}


/**
* 関数 CommentOutJS( arg0, arg1, arg2, arg3 ) // CommentOutJS( st, p1, p2, ast )
*
* ※ 行頭のインデントを維持して字下げされた位置でコメントアウトするパターン(コメントドキュメント向け)
*  ・選択範囲内の最小の字下げ位置にあわせる。
*  ・基本的に「JS アンコメント」してもレイアウトを保持できるが、
*    各行の字下げルールが同じである前提なので、半角スペースもタブコードも1文字として数える。
*  ・空白文字だけの行は空行と見做し、行頭記号 " * " を付けた後ろに空白文字を残さない。
*/
function CommentOutJS( str, p1, p2, ast ) {
  var a = str.split( "\n" );
  var b = [];


    case 43: // case 41 & 42 の JavaScript コメント をアンコメントする
   // 各行の字下げ数からの最小値を取得
      /*
   for ( var i = 0, len = a.length; i < len; i ++ ) {
      * ・この文章のようなインデントされたコメントブロックの字下げ位置を考慮するが、
     var id = a[i].search( /[^ \t]/ ); // 字下げの空白文字数を取得(空白行では -1)
      *   先頭のコメントマーク "/*" のスラッシュの前の字下げ(空白部分)が基準となる。
    b.push( id < 0 ? 100000 : id ); // ※ -1 は sort のジャマなのでデタラメな数値に置きかえる
      * ・複数のコメントブロックが選択範囲内にある場合、最初のコメントブロックしかアンコメントしない。
  }
      * ・中間行の行頭記号はアスタリスク「*」と全角/半角の中黒「・」「・」を削除対象とする。
  // 配列 b を昇順で並びかえ(先頭行から最小の字下げ部分の「空白文字 ␣␣ 」を取得)
      *   (行頭記号と前後の半角スペース各1を削除する)
  b.sort( function( a, b ) { return ( a < b ) ? -1 : ( a > b ) ? 1 : 0; } );
      * ・JSコメントでない箇条書き文で実行した場合も行頭記号を削除する。
  var blanc = a[0].slice( 0, b[0] );
      *
      * ▼ 注意事項 ▼
      * ・選択範囲がJSコメントか箇条書き文であれば、選択範囲の先頭/末尾の余計な空白行も削除する。
      * ・中間行の末尾空白文字も削除し、空白行ならインデント部分も削除する。
      *
      * コメントマークは 配列 [ "接頭辞" , "接尾辞" , "中間行の行頭記号" ] で用意する。
      *     各要素はあらかじめJSの正規表現で記述しておくこと。
      */
      // コメントの"接頭辞"と"接尾辞"と"行頭記号"を正規表現で配列に格納
      var p = new Array( "\\/\\*+ ?" , " ?\\*\\/" , " ?(\\*|[・・]) ?" );
      // コメントアウトを解除
      var dc = deleteComment( st, p )
      // 選択範囲に JSコメント がなかった場合 undo 履歴を残さない
      if ( dc == st ) {
        if ( pos ) { s.SetActivePos( pos );  Quit(); }
        break;
      }
      // 先頭と末尾の空行を削除してアンコメント完了
      var blank = /[\t  ]*$/gm;
      s.Text = dc.replace( blank , "" ).replace( /^[\s ]*\n|\n[\s ]*$|/g , "" );
      break;


  // 字下げ位置に中間行の行頭記号 " * " を追加
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    if ( /^[ \t]*$/.test( a[i] ) ) { a[i] = blanc + ast; } // 空白行
    else { a[i] = blanc + ast + a[i].slice( b[0] ); }
  }


    case 45: // case 44 の <!--␣ XMLコメント ␣--> をアンコメントする
  var prefix = blanc + p1 + "\n"; // 接頭辞
      // 選択範囲内のコメントマークをすべて削除
  var suffix = "\n" + blanc + p2; // 接尾辞
      var dc = st.replace( / ?<!-- ?| ?-- *> ?/g , "" );
  return prefix + a.join( "\n" ) + suffix;
      // 選択範囲に <!-- XMLコメント --> がなかった場合 undo 履歴を残さない
}
      if ( dc == st ) {
        if ( pos ) { s.SetActivePos( pos );  Quit(); }
        break;
      }
      // アンコメント完了
      s.Text = dc
      break;


/**
* 関数 DeleteComment( arg1, arg2 )
*
* 複数のコメントブロックが選択範囲内にある場合、最初のコメントブロックしかアンコメントしない
* 引数 arg2 は 配列[ "接頭辞" , "接尾辞" , "中間行の行頭記号" ] で、
*  各要素はあらかじめ JavaScript の正規表現で記述されていないとダメ
*  arg2 = p = [ "\\/\\*+ ?" , " ?\\*\\/" , " ?(\\*|[・・]) ?" ];
*/
function DeleteComment( str, p ) {
  var a = str.split( "\n" ), len = a.length;
  var hit = false, line0 = 0, line1 = len;


     default:
  // コメントの接尾辞と接尾辞を検索・置換する
      break;
  for ( var j = 0, reg1; j < 2; j ++ ) {
     // 接頭辞 p[0], 接尾辞 p[1] の検索用
    reg1 = new RegExp( p[j], "" );


    for ( var i = 0; i < len; i ++ ) {
      if ( reg1.test( a[i] ) ) {
        a[i] = a[i].replace( reg1, "" );
        // 接頭辞 p[0] がヒットした行
        if ( j == 0 ) { line0 = i;  hit = true;  break; }
        // 接尾辞 p[1] がヒットした行
        else { line1 = i;  break; }
      }
    }
   }
   }


   // 選択範囲を復元(選択範囲を 移動/コピー/切り取り しやすいように末尾改行まで含める)
   // 中間行の行頭記号 p[2] (アスタリスク、中黒)を検索・削除
   s.SetActivePos( s.GetActivePos() + 1 );
  // 行頭空白文字の後ろの2文字までを置換対象にする
   s.SetAnchorPoint( mePosLogical, 1, ay );
   var reg2 = new RegExp( "^[ \\t]*" + p[2], "" ); // 行頭空白+行頭記号の検索用
   var reg3 = new RegExp( p[2], "" ); // 行頭記号の置換(削除)用


   // 選択範囲の中身が ^\n のみなら選択解除
   // 接頭辞(よりも前)の行と接尾辞(よりも後ろ)の行は、検索・置換の対象外
   if ( s.Text.match( /^\n$/g ) ) s.SetActivePos( s.GetAnchorPos() );
  for ( var i = line0, limit = Math.min( len, line1 ), id, a1, a2;
   i < limit; i ++ ) {
    // 行頭記号がヒットしたら
    if ( reg2.test( a[i] ) ) {
      // 置換範囲(空白文字数+2文字)
      id = a[i].indexOf( a[i].match( /[^ \t]/ ) ) + 2;
      a1 = a[i].slice( 0, id ).replace( reg3, "" );
      a2 = a[i].slice( id );
      a[i] = a1 + a2;
    }
  }


   ScrollX = sx; ScrollY = sy; // スクロール位置を復元
   // 各行の行末空白文字と、先頭/末尾の空行を削除
   Redraw = true;
   return a.join( "\n" )
          .replace( /[\t  ]*$/gm, "" )
          .replace( /^[\s ]*\n|\n[\s ]*$/g, "" );
}
}


 
/**
/* 関数 insertQuote( arg1, arg2 ) */
* 関数 GetTag( tagType, tagKey, property )
  // Kuro版まま
* 指定された Tag の値を返す
function insertQuote( arg1, arg2 ) {
*/
   var a = arg1.split( "\n" );
function GetTag( tagType, tagKey, property ) {
  for ( var i = 0; i < a.length; i ++ )
   try {
     a[i] = arg2 + a[i];
    var obj = ( typeof tagType === "object" ) ? tagType
   return a.join( "\n" );
            : ( tagType === 1 ) ? editor.ActiveDocument
            : ( tagType === 2 ) ? editor
            : ( tagType === 3 ) ? window
            : window;
    return ( obj.Tag.Exists( tagKey )
    && ( property ? property in obj.Tag( tagKey ) : true ) )
     ? property
      ? obj.Tag( tagKey )[ property ]
      : obj.Tag( tagKey )
    : null;
   } catch( e ) { Status = e;  return null; }
}
}


 
/**
/* 関数 deleteQuote( arg1 ) */
* 関数 SetTag( value, tagType, tagKey, property )
  // 各行ごとに、配列 q の並び順で最初にマッチした引用符を削除
* 指定された値を Tag に書き込む
  // Kuro版から
*/
  //  ①変数名を変更
function SetTag( value, tagType, tagKey, property ) {
  //  ②最後の if 文の「break;」を補遺し、「1つ削除」の不具合を修正
   try {
function deleteQuote( arg1, arg2 ) {
    var obj = ( typeof tagType === "object" ) ? tagType
   var a = arg1.split( "\n" );
            : ( tagType === 1 ) ? editor.ActiveDocument
  for ( var i = 0; i < a.length; i ++ ) {
            : ( tagType === 2 ) ? editor
    for ( var j = 0; j < q.length; j ++ ) {
            : ( tagType === 3 ) ? window
      if ( q[j].length == 0 )
            : window;
        continue;
    if ( property ) {
      var qt = q[j];
       if ( obj.Tag.Exists( tagKey ) ) {
       if ( a[i].substr( 0, qt.length ) == qt ) {
         obj.Tag( tagKey )[ property ] = value;
         a[i] = a[i].substr( qt.length );
        break;
       }
       }
      else { obj.Tag( tagKey ) = { property: value }; }
     }
     }
    else { obj.Tag( tagKey ) = value; }
   }
   }
   return a.join( "\n" );
   catch( e ) { Status = e; }
  finally { return; }
}
}


/**
* 関数 AddStrPrompt( tagType, tagKey )
* 「任意の文字列」コマンド
* 入力ダイアログで指定された文字列を返す
*/
function AddStrPrompt( tagType, tagKey ) {
  // 前回使用した文字列があればダイアログの初期値に再利用
  var str = "";
  if ( tagType && ( t = GetTag( tagType, tagKey, "addStr" ) ) ) {
    str = t;
  }
  // 入力ダイアログ
  var msg = "につける文字列:\t"
          + "改行 = \\\\\\n ; タブ = \\\\\\t  (注:¥記号3つ)";
  p = Prompt( "前" + msg, str ).replace( /\\\\\\t/g, "\t" )
                              .replace( /\\\\\\n/g, "\n" );
  if ( p && tagType ) {
    SetTag( p.replace( /\t/g, "\\\\\\t" ).replace( /\n/g, "\\\\\\n" )
    , tagType, tagKey, "addStr" );
  }
  return p;
}


/* 関数 CommentOutJS( arg1, arg2, arg3, arg4 ) */
/**
function CommentOutJS( arg1, arg2, arg3, arg4 ) {
* 関数 DelStrPrompt( tagType, tagKey )
   var a = arg1.split( "\n" ); // 選択範囲 st を "\n" で区切って配列 a に
* 「任意の文字列を削除」コマンド
  var id = a[0].search( /[^  \t]/ ); // 先頭行の文字列中で「非空白文字」が最初にあらわれる位置
* 入力ダイアログで指定された文字列を返す
   var blanc = a[0].slice( 0, id ); // 先頭行の行頭の「空白文字列 ␣ 」を取得
*/
  var re = new RegExp( blanc , "" ); // 検索フラグつきの正規表現変数に格納
function DelStrPrompt( tagType, tagKey ) {
  var _pre = blanc + arg2 + "\n"; // "/*" の前に「空白文字列 ␣ 」、後ろに改行
  // 前回使用した文字列があればダイアログの初期値に再利用
   var _sur = "\n" + blanc + arg3; // " */" の前に改行と「空白文字列 ␣ 」
   var str = "";
  if ( tagType && ( t = GetTag( tagType, tagKey, "delStr" ) ) ) {
    str = t;
  }
  // 入力ダイアログ
  var msg = "から削除する文字列:\t"
          + "タブ = \\\\\\t  (注:¥記号3つ)";
   p = Prompt( "先頭(行頭)" + msg, str ).replace( /\\\\\\t/g, "\t" );
  if ( p && tagType ) {
    SetTag( p.replace( /\t/g, "\\\\\\t" ), tagType, tagKey, "delStr" );
  }
   return p;
}


  // 各行の先頭の空白文字列を削除し、「空白文字列」と ast = " * " を追加する
/**
  for ( var i = 0; i < a.length; i ++ )
* 関数 ToHalfWidth( strVal )
    a[i] = blanc + arg4 + a[i].replace( re , "" );
* 全角英数記号を半角変換して返す
   // 各行を "\n" で区切って連結し、先頭に _pre = "␣/*\n"、末尾に _sur = "\n␣ */" を付け足す
*/
  return _pre + a.join( "\n" ) + _sur;
function ToHalfWidth( strVal ){
   // 半角変換(文字コードをシフト)
  return strVal.replace( /[!-~]/g, function( tmpStr ) {
    return String.fromCharCode( tmpStr.charCodeAt(0) - 0xFEE0 );
  } );
}
}


/**
* 関数 DelByNumPrompt()
* 「任意の文字数を削除」コマンド
* 入力ダイアログで指定された文字列から
* 数字を抽出して半角数字にして返す
*/
function DelByNumPrompt() {
  var msg = "から削除する文字数 (数字のみ有効):";
  return ToHalfWidth( Prompt( "先頭(行頭)" + msg, "" )
        ).replace( /\D/g , "" ); // 半角に変換して数字以外の文字は削除
}


/* *関数 deleteComment( arg1, arg2 ) */
  /*
  * 複数のコメントブロックが選択範囲内にある場合、最初のコメントブロックしかアンコメントしない
  * 引数 arg2 は 配列[ "接頭辞" , "接尾辞" , "中間行の行頭記号" ] で、
  *  各要素はあらかじめJSの正規表現で記述されていないとダメ
  */
function deleteComment( arg1, arg2 ) {
  var a = arg1.split( "\n" ); // 選択範囲 st を "\n" で区切って配列 a に
  var _reg,  _re,  _id,  _a1,  _a2;
  var _hit = false,  _line0 = 0,  _line1 = a.length; // 初期化の必要そうな変数


   // コメントの接頭辞と接尾辞を検索・置換する
/**
   for ( var j = 0; j < 2; j ++ ){
* 関数 MultiFunction( Fn, arg1 )
     if ( arg2[j] == "" ) // 接頭辞 p[0], 接尾辞 p[1] が定義されていないならスルー
* マルチカーソル(複数選択範囲)に対応させる
       continue;
* 第1引数: Function; 選択範囲ごとに適用する処理の関数
    // 先頭行から接頭辞 p[0], 接頭辞 p[1] を検索し、置換処理(削除)する
* 第2引数以降: Function に渡す引数をまとめた配列
    for ( var i = _line0; i < a.length; i ++ ) {
*/
      _reg = RegExp( arg2[j] , "" );
function MultiFunction( Fn, arg ) {
      if ( a[i].match( _reg ) ) {
  var d = editor.ActiveDocument;
        a[i] = a[i].replace( _reg , "" );
  var s = d.selection;
        // 接頭辞を処理したら接尾辞の処理へ
 
        if ( j == 0 ) {
   // 矩形選択範囲は行に分ける
          _hit = true; // ヒットフラグ = true
  s.Mode = meModeMulti;
          _line0 = i; // 接頭辞がヒットした行
 
          break;
  // 選択範囲の座標を取得
        }
  var sCount = s.Count;
        // 接尾辞を処理したらループを抜ける
  var Sel = [];
        else { // ( j == 1 )
   for ( var i = 0; i < sCount; i ++ ) {
          _line1 = i; // 接尾辞がヒットした行
     Sel[i] = {
          break;
      act: s.GetActivePos( i ),
        }
       anc: s.GetAnchorPos( i )
      }
    };
    }
  }
 
  // 各選択範囲を処理
  for ( var i = 0, diff = 0, dl; i < sCount; i ++ ) {
    dl = d.TextLength;
    s.SetActivePos( Sel[i].act + diff );
    s.SetAnchorPos( Sel[i].anc + diff );
 
    Fn( arg ); // LineCommentQuote_Main() 関数
 
    // Fn() の残した選択範囲(またはキャレット位置)を回収
    Sel[i].act = s.GetActivePos();
    Sel[i].anc = s.GetAnchorPos();
    diff += d.TextLength - dl; // 文字数の増減量(累積)
   }
   }


   // 中間行の行頭記号 p[2] (アスタリスク、中黒)を検索・置換する
   // マルチカーソル(複数選択範囲)を復帰
   if ( arg2[2].length ) {
   for ( var i = 0; i < sCount; i ++ ) {
    // 接頭辞(よりも前)の行と接尾辞(よりも後ろ)の行は、検索・置換の対象外にする
    s.AddPos( Sel[i].anc, Sel[i].act );
    for ( var i = ( _hit ) ? _line0 + 1 : 0; i < _line1; i ++ ) {
      _re = RegExp( "^[  \\t]*" + arg2[2] , "" );
      // 行頭記号がヒットしたら行頭空白文字の後ろの2文字までを置換処理する
      if ( a[i].match( _re ) ) {
        _id = a[i].indexOf( a[i].match( /[^  \t]/ ) ) + 2;
        _reg = RegExp( arg2[2] , "" );
        _a1 = a[i].slice( 0, _id ).replace( _reg , "" );
        _a2 = a[i].slice( _id );
        a[i] = _a1 + _a2;
      }
    }
   }
   }
  // 各行を "\n" で区切って連結しなおす
  return a.join( "\n" );
}
}
</source>
</syntaxhighlight>


== 謝辞 ==
== 謝辞 ==
Kuro 氏の「引用の追加」は Mery のマクロの勉強をはじめたきっかけになったマクロです。 <br>
Kuro 氏の「引用の追加」マクロは Mery のマクロの勉強をはじめたきっかけになったマクロです。
文字列操作、ポップアップメニューの使い方、JavaScript の配列や関数の使い方、if 文、switch 文、for 文、etc... 入門者の "とっかかり" として最適なマクロだったとおもいます(※もとの「引用の追加」は、このページのものよりもシンプル&コンパクトなマクロでした)。<br>
 
文字列操作、ポップアップメニューの使い方、JavaScript の配列や関数の使い方、if 文、switch 文、for 文、etc... 入門者の "とっかかり" として最適なマクロだったとおもいます(※もとの「引用の追加」は、このページのものよりもシンプル&コンパクトなマクロでした)。
 
たいへん有用なマクロを作ってくださった Kuro 氏に感謝申し上げます。
たいへん有用なマクロを作ってくださった Kuro 氏に感謝申し上げます。


残念ながら「引用の追加」マクロは公開停止になってしまったので、この度わたしの手元でカスタマイズしたものを公開させていただきました。 <br>
残念ながら「引用の追加」マクロは公開停止になってしまいましたので、この度わたしの手元でカスタマイズしたものを公開させていただきました。
改訂版の公開にご承諾いただいた Kuro 氏に重ねて御礼申し上げます。 (sukemaru)
 
改訂版の公開について承諾していただいた Kuro 氏に重ねて御礼申し上げます。 (sukemaru)

2023年5月21日 (日) 04:46時点における最新版

画像は 2019/04/07 版のものです。

2020/06/23 版では、サブメニューに削除系コマンドをまとめてあります。

引用符/コメント[編集]

Kuro 氏の「引用の追加」マクロのコードを改変しました。

  • ポップアップメニューから任意の 引用マーク箇条書きの行頭記号行コメントの記号 などの種類を選択して、選択範囲をふくむの各行の先頭に追加します。選択範囲がないばあいはカーソル行の先頭に挿入します。
  • 行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで末尾改行が含まれているばあい、さいごの改行を無視します。
  • 行頭に挿入する文字列として クリップボード の文字列データや 入力ダイアログ で指定した文字列を使用することもできます。
・「クリップボード」の機能は「行の先頭に貼り付け」マクロとおなじものです。

・「任意の文字列」は改行コードやタブ文字も記述できますが、それぞれ入力ダイアログで「\\\n」と「\\\t」で入力されたもの (注:¥記号3つ) を改行コードとタブ文字に置換するようにしてあります。
※「\n」や「\t」と記述したばあい、そのままの文字列として「\n」や「\t」が返されます。

挿入/削除できる引用マークやコメントマーク[編集]

  • 各行の先頭にメタ記号を追加
ポップアップメニュー内に表示するラベル(注釈)や並び順をカスタマイズすると、Markdown 用のマークアップなどに活用しやすくなります。
以下は、公開・配布しているソースコードの初期状態で利用できる引用マークやコメントマークです。
  • がついたものは、半角スペースつきで記号を挿入します。
  • 「1つ削除」/「すべて削除」では、記号のうしろの半角スペースの有無を区別しません。
  • 」中黒 の半角差分の 「」半角カナの中黒(U+FF65)と、「·」欧文用ユニコード文字のビュレット(U+00B7) を削除対象として追加してあります。
> ␣ 		(メール 引用マーク)
>> 		(BBS アンカー記号)

 		(箇条書き 全角中黒)
␣ * ␣ 		(箇条書き アスタリスク)
* ␣ 		(箇条書き アスタリスク)
- ␣ 		(箇条書き 半角ハイフンマイナス)
 		(注意書き ※印)

␣ 		(半角スペース)
☐ 		(全角スペース)
› 		(TABコード)
⏎ 		(空行: 改行コード) ※削除コマンドからの削除不可

// ␣ 		(C系, JavaScript コメント)
# ␣ 		(Perl, Ruby, Python コメント)
; ␣ 		(INI コメント)
' ␣ 		(VB コメント)
-- ␣ 		(SQL コメント)
: ␣ 		(MS-DOS ラベル)
:: ␣ 		(BAT コメント)
REM ␣ 		(BAT コメント)
※以下の3種は、「1つ削除」/「すべて削除」ではアンコメントされません。ポップアップメニュー内にそれぞれ専用の "アンコメント" コマンドがあります)
  • 選択範囲の行全体をひとまとめでコメントアウト
<!-- (XML コメント) -->

/* (C系, JavaScript コメント) */
  • 選択範囲の行全体を複数行形式でコメントアウト(※字下げ位置でコメントアウトします)
/*
 *  (C系, JavaScript ブロックコメント)
 */
削除系コマンド
  • 1つ削除
選択範囲内の各行の行頭から、設定項目の「引用符の種類」に登録されている記号や文字列と一致するものを1つずつ削除します (※ 改行記号 "\n" は対象外 ⇒ 「空行を削除」コマンド)。
  • すべて削除
選択範囲内の各行の行頭から、設定項目の「引用符の種類」に登録されている記号や文字列と一致するものをすべて削除します (※ 改行記号 "\n" は対象外)。
  • 空行を削除
選択範囲内の空行を削除します。
  • 行頭の空白文字を削除
選択範囲内の各行の行頭から、全角/半角空白とタブ文字をすべて削除します。
※ このマクロでは、行末の空白文字列の削除はできません ( ⇒ 「カッコで囲う」マクロや「テキスト整形」マクロを利用してください)。
  • 行頭から任意の文字列を削除
選択範囲内の各行の行頭から、入力ダイアログで指定された文字列を削除します。
  • 行頭から任意の文字数を削除
選択範囲内の各行の行頭から、入力ダイアログで指定された文字数だけ削除します。
ポップアップメニューの既存の項目を減らしたいばあいは、ソースコード内の "m.Add( … );" の行を // でコメントアウトするとその項目をメニューから隠せます。ただし、メニューから隠れるだけで、「1つ削除」/「すべて削除」の対象から除外されるわけではありません。

ダウンロード[編集]

ダウンロード: 「ファイル:引用符/コメント.zip」(アイコン入り)

  • 第四版: 2020/06/23
コマンドを追加: 「任意の文字数を削除」
マルチカーソル/複数選択範囲に対応
  • 第三版: 2019/04/07
コマンドを追加: 「空行の追加」、「任意の文字列を削除」
  • 第二版: 2018/10/30
  • 第一版: 2018/10/28

ソースコード[編集]

#title = "引用符を追加..."
#tooltip = "引用符/コメントマークを追加・削除"
#icon = "quote2[3].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",96

/**
 * -----------------------------------------------------------------------------
 * 引用の追加		( => 2018/10/14 公開停止)
 * Orginal Copyright (c) Kuro. All Rights Reserved.
 * www:    http://www.haijin-boys.com/
 * -----------------------------------------------------------------------------
 * Modified by sukemaru	(2018/10/28 - 2020/06/23)
 * 「引用符を追加」または「引用符/コメント」
 * 選択範囲の行頭に引用符/コメントマークを追加・削除する
 * -----------------------------------------------------------------------------
 * ▼ Kuro 版「引用の追加」マクロからの変更点 ▼
 * 
 * ・ポップアップメニューの体裁を変更した。
 * ・引用符の種類を増やした(※ 基本的に「メタ文字+半角スペース」)。
 * ・「クリップボード」と「任意の文字列」を追加。
 * ・配列に削除用の要素(半角スペースなしのメタ文字のみの差分)も余分に追加した。
 *   ※「すべて削除」では、半角スペース、全角スペース、タブ文字での字下げをすべて削除する。
 *   ※「クリップボード」、「任意の文字列」、「空行」、「JS/XML コメントアウト」は、
 *     「1つ削除//すべて削除」では削除されない。
 * 
 * ・選択範囲があったときには行全体に拡張・復帰するようにした。
 * ・選択範囲なしの状態からカーソル行にたいして「追加/1つ削除/すべて削除」を実行したときは、
 *   実行前の位置にカーソルを返せるようにした。
 * ・「1つ削除」の不具合箇所を修正した。
 */

// ---------- ▼ 設定項目 ▼ ---------- //

// ■ 「任意の文字列」で入力した文字列の一時記憶方法
var tagType = 2;
  // 0 : 一時記憶なし
  // 1 : タブ(文書)ごとに一時記憶する(Document.Tag)
  // 2 : ウインドウごとに一時記憶する(Editor.Tag)
  // 3 : すべてのタブとウインドウ共通で一時記憶する(window.Tag)


// ■ 引用符の種類(追加用)
var q = [ "" ,		// 以下 r = 1~10、11~20、21~30、31~ の ID 順
  "> " ,  "・" ,  " * " ,  "- " ,  " " ,  " " ,  "\t" ,  "// " ,  "# " ,  "; " ,
  "' " ,  "-- " ,  ": " ,  ":: " ,  "REM " ,  "※" ,  ">>" ,  "* " ,  "" ,  "" ,
  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,
  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,  "" ,
"" ];


/* 
 * ※半角スペースの有無で「1つ削除/すべて削除」がマッチしなくなるので、
 *   以下に半角スペース あり/なし の差分要素を適当に追加してあります。
 * ※半角スペース差分(中黒=ビュレットは全角/半角差分も)の変更は、配列内の編集ではなく
 *   ポップアップメニュー項目のID(番号)変更で対応しないと、「1つ削除/すべて削除」が効かなくなります
 * (同一文字をふくむ要素は文字列の長いものが先に置かれていないとダメ)。
 * 「・」は半角カナの中黒(U+FF65)、「·」は欧文用ユニコード文字のビュレット(U+00B7)
 */
// ■ 引用符の種類(削除用差分)
var qq = [
  ">" ,  "・ " ,  "・" ,  "· " ,  "·" ,  "*" ,  "-" ,  "//" ,  "#" ,  ";" ,
  "'" ,  "--" ,  ":" ,  "::" ,  "" ,  "" ,  ""
];
q = q.concat( qq );

// ---------- ▲ 設定項目 ▲ ---------- //

var d = editor.ActiveDocument;
var s = editor.ActiveDocument.selection;
var m = CreatePopupMenu();

if ( d.ReadOnly ) {
  m.Add( " ドキュメントは 書き換え禁止 です & ", 0 );
}

else {
  var cb = ClipboardData.GetData();	// クリップボードのテキストデータを取得

  // ポップアップメニューの項目とID
  // m.Add( "ラベル", r ); の各行は、任意に上下移動(並べ替え)してよいが、
  // r の数値は上の配列 q の並び順やテキスト変換処理の case r: に対応しているので変更しないこと!

  m.Add( "?	任意の文字列 (&E)...", 1010 );
  m.Add( "[ … ]	クリップボード (&C)", 1000, !cb *2 );

  m.Add( "", 0, meMenuSeparator );
  m.AddPopup( "▲	削除 (&D)", sm1 = CreatePopupMenu() );
    sm1.Add( "●	1つ削除 (&D)", 1013 );
    sm1.Add( "●	すべて削除 (&A)", 1014 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( " ↲ 	空行を削除 (&B)", 1015 );
    sm1.Add( "␣␣	行頭の空白文字を削除 (&S)", 1016 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "?	行頭から任意の文字列を削除 (&Q)...", 1011 );
    sm1.Add( "? 	行頭から任意の文字数を削除 (&X)...", 1012 );

  m.Add( "", 0, meMenuSeparator );
  m.Add( "> 	> メール引用符 (&>)", 1 );
  m.Add( ">>	>> BBS アンカー (&>)", 17 );
  m.Add( "・	・ 箇条書き (&/)", 2 );
  m.Add( " * 	* 箇条書き (&*)", 3 );
  m.Add( "* 	* 箇条書き (&W)", 18 );
  m.Add( "- 	- 箇条書き (&-)", 4 );
  m.Add( "※	※注意書き (&K)", 16 );

  m.Add( "", 0, meMenuSeparator );
  m.Add( "␣	半角スペース (&1)", 5 );
  m.Add( "⃞	全角スペース (&2)", 6 );
  m.Add( "›	タブコード (&T)", 7 );
  m.Add( "⏎	空行 (&N) ...", 1006 );

  m.Add( "", 0, meMenuSeparator );
  m.Add( "\/\/ 	JS・C コメント (&J)", 8 );	// アクセラレータは「JS コメントアウト」と重複
  m.Add( "# 	Perl コメント (&P)", 9 );
  m.Add( "; 	INI コメント (&I)", 10 );
  m.Add( "’ 	VB コメント (&V)", 11 );
  m.Add( "-- 	SQL コメント (&S)", 12 );
  m.Add( ": 	MS-DOS ラベル (&M)", 13 );
  m.Add( ":: 	BAT コメント (&B)", 14 );
  m.Add( "REM 	BAT コメント (&R)", 15 );

  m.Add( "", 0, meMenuSeparator );
  m.Add( "/*  *  */	JS コメントアウト 2 (&J)", 1002 );
  m.Add( "/*  */	JS コメントアウト 1  (&J)", 1001 );
  m.Add( "	JS アンコメント (&U)", 1003 );
  m.Add( "", 0, meMenuSeparator );
  m.Add( "<!--  -->	XML コメントアウト (&X)", 1004 );
  m.Add( "	XML アンコメント (&L)", 1005 );

  m.Add( "", 0, meMenuSeparator );
  m.Add( "キャンセル	& ", 0 );
}

// ポップアップメニューの表示
// m.Track(0); ならキャレット位置、m.Track(1); ならカーソル位置にサブメニューがポップアップ
var r = m.Track( mePosMouse = 1 );

if ( r > 0 ) {
  var p;
  var tagKey = "LineCommentQuote";
  if ( r === 1010 ) { p = AddStrPrompt( tagType, tagKey ); }
  if ( r === 1011 ) { p = DelStrPrompt( tagType, tagKey ); }
  if ( r === 1012 ) { p = DelByNumPrompt(); }	// 「任意の文字数を削除」

  var sx = ScrollX,  sy = ScrollY;
  // マルチカーソル対応
  var arg = [ q, r, p, cb ];
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! s.Mode || s.Mode === meModeStream ) {
    LineCommentQuote_Main( arg );
  }
  // 矩形選択または複数選択のとき
  else {
    BeginUndoGroup();
    AddUndo();
    MultiFunction( LineCommentQuote_Main, arg );
    EndUndoGroup();
  }
  ScrollX = sx;  ScrollY = sy;
}


/**
 * 関数 LineCommentQuote_Main( [ q, r, p, cb ] )
 * 「引用符/コメント」マクロ
 */
function LineCommentQuote_Main( arg ) {
  var q  = arg[0];
  var r  = arg[1];
  var p  = arg[2];
  var cb = arg[3];

  // 選択範囲
  var d = editor.ActiveDocument;
  var s = editor.ActiveDocument.selection;
  var pos = s.IsEmpty ? s.GetActivePos() : -1;
  var tx = s.GetTopPointX( mePosLogical );
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  // 選択範囲の末尾が行頭にあるときの調整
  if ( ty < by && bx == 1 && d.Text.charAt( s.GetActivePos() ) ) {
    by --;
  }
  // 選択範囲を拡張
  s.SetActivePoint( mePosLogical, 1, by );
  s.EndOfLine( false, mePosLogical );
  s.SetAnchorPoint( mePosLogical, 1, ty );

  // 選択範囲の文字列を取得
  var st = tmp = s.Text;
  var exit = false;	// Quit の代用フラグ

  // IDごとのテキスト変換処理
  switch ( r ) {

  // 引用符/コメントマークを追加
  case 1:  case 2:  case 3:  case 4:  case 5:
  case 6:  case 7:  case 8:  case 9:  case 10: 
  case 11:  case 12:  case 13:  case 14:  case 15:
  case 16:  case 17:  case 18:
    // 各行の先頭に引用符/コメントマークを追加
    s.Text = st.replace( /^/gm, q[r] );
//     /* とりあえずコメントアウトしておく */ 
//     // マクロ実行前に選択範囲がなかった場合は、カーソルを元の位置に戻す
//     if ( pos > -1 ) {
//       s.SetActivePos( pos + q[r].length );
//       exit = true;
//     }
    break;

  // クリップボード
  case 1000:
    s.Text = st.replace( /^/gm, cb );
    if ( pos > -1 ) { s.SetActivePos( pos + cb.length );  exit = true; }
    break;

  // 空行を挿入	※空行は削除コマンドの削除対象に含まれない
  case 1006:
    var n = "\n";	// 空改行
    s.Text = st.replace( /^/gm, n );
    if ( pos > -1 ) { s.SetActivePos( pos + n.length );  exit = true; }
    break;

  // 任意の文字列(テキストボックス)
  case 1010:
    if ( p ) { s.Text = st.replace( /^/gm, p ); }
    if ( pos > -1 ) { s.SetActivePos( pos + p.length );  exit = true; }
    break;


  // 任意の文字列を削除
  case 1011:
    var reg = new RegExp(
      "^" + p.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" )
    , "gm" );
    tmp = st.replace( reg, "" );
    if ( tmp !== st ) {
      s.Text = tmp;	
      if ( pos > -1 && tmp.length ) {
        s.SetActivePos( pos - ( st.length - tmp.length ) );
        exit = true;
      }
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;

  // 任意の文字数を削除
  case 1012:
    if ( p && st ) {
      tmp = DeleteCharByNum( st, p );
      if ( tmp !== st ) {
        s.Text = tmp;
        if ( pos > -1 && tmp.length ) {
          s.SetActivePos( pos - ( st.length - tmp.length ) );
          exit = true;
        }
      }
      else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    }
    break

  // 1つ削除
  case 1013:
    // 各行ごとに、配列 q の並び順で最初にマッチした引用符/コメントマークを削除
    tmp = DeleteQuote( st, q );
    if ( tmp !== st ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length ) {
        s.SetActivePos( pos - ( st.length - tmp.length ) );
        exit = true;
      }
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;

  // すべて削除
  case 1014:
    var org = st;	// DeleteQuote() のループ処理前のテキスト
    // st を最大40回 DeleteQuote() でループ処理
    for ( var i = 0; i < 40; i ++ ) {
      tmp = DeleteQuote( st, q );
      // DeleteQuote() 処理の前後でテキストが一致したらループを抜ける
      if ( tmp == st ) { break; }
      st = tmp;		// DeleteQuote() したテキスト tmp を st に再代入
    }
    if ( tmp !== org ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length) {
        s.SetActivePos( pos - ( org.length - tmp.length ) );
        exit = true;
      }
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;

  // 空行を削除
  case 1015:
    // キャレット位置が空行上のとき
    if ( pos > -1 && tx == 1 && d.GetLine( ty, 0 ) == "" ) {
      s.Delete();  exit = true;
    }
    else {
      tmp = st.replace( /\n+/g, "\n" );
      if ( st !== tmp ) { s.Text = tmp; }
      else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    }
    break;

  // 行頭の空白文字を削除
  case 1016:
    tmp = st.replace( /^[\t  ]+/gm, "" );
    if ( tmp !== st ) {
      s.Text = tmp;
      if ( pos > -1 && tmp.length ) {
        s.SetActivePos( pos - ( st.length - tmp.length ) );
        exit = true;
      }
    }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;


  /* JavaScript コメントアウト1 */
  // <!-- XML コメントアウト -->   
  case 1001:  case 1004:
    // 「引用の追加」では行単位に拡張した選択範囲をまとめてコメントアウトするので、
    // 行の中間部分だけをコメントアウトするなら「カッコで囲う」マクロを使うこと。
    var p1 = ( r == 1001 ) ? "/\* " : "<!-- ";
    var p2 = ( r == 1001 ) ? " */"  : " -->";
    s.Text = p1 + st + p2;
    if ( ! st ) {
      s.SetActivePos( pos + p1.length );  exit = true;
    }
    break;

  /* * JavaScript コメントアウト2 */
  case 1002:
    var p1 = "/\**",  p2 = " */",  ast = " * ",  n = "\n";
    s.Text = CommentOutJS( st, p1, p2, ast );
    // マクロ実行前に空行だった場合はカーソルをコメント枠のなかに移動
    if ( pos > -1 ) {
      s.SetActivePos( pos + ( p1 + n + ast ).length  );
      exit = true;
    }
    // カーソルを接頭辞のうしろに移動
    else {
      s.SetActivePoint( mePosLogical, 1, ty );
      s.EndOfLine();  exit = true;
    }
    break;

  /* JSアンコメント */	// ※選択範囲内の各行頭のコメントマークにのみマッチ
  // case 41 & 42 の JavaScript コメント をアンコメントする
  case 1003:
    // コメントの "接頭辞" と "接尾辞" と "行頭記号" を正規表現で配列に
    var p = new Array( "\\/\\*+ ?" , " ?\\*\\/" , " ?(\\*|[・・]) ?" );
    tmp = DeleteComment( st, p )
    if ( tmp !== st ) { s.Text = tmp; }	// アンコメント完了
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;

  /* XML アンコメント */
  // case 44 の <!--␣ XMLコメント ␣--> をアンコメントする
  case 1005:
    tmp = st.replace( / ?<!-+ ?| ?-+ *> ?/g , "" );
    if ( tmp !== st ) { s.Text = tmp; }
    else if ( pos > -1 ) { s.SetActivePos( pos );  exit = true; }
    break;

  default:
    break;
  }	// end switch(r)

  // 選択範囲を復元
  if ( ! exit ) {
    // ※移動/コピー/切り取り しやすいように末尾改行まで含める
    s.SetActivePos( s.GetActivePos() + 1 );
    s.SetAnchorPoint( mePosLogical, 1, ty );

    // 選択範囲の中身が \n のみなら選択解除
    if ( /^\n$/.test( s.Text ) ) {
      s.SetActivePos( s.GetAnchorPos() );
    }
  }
}


/* 関数 DeleteQuote( str, q ) */
function DeleteQuote( str, q ) {
  var a = str.split( "\n" );
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    for ( var j = 0, qLen = q.length, qt; j < qLen; j ++ ) {
      qt = q[j];
      if ( ! qt ) { continue; }
      if ( a[i].substr( 0, qt.length ) === qt ) {
        a[i] = a[i].substr( qt.length );
        break;
      }
    }
  }
  return a.join( "\n" );
}

/**
 * 関数 CommentOutJS( arg0, arg1, arg2, arg3 )	// CommentOutJS( st, p1, p2, ast )
 *
 * ※ 行頭のインデントを維持して字下げされた位置でコメントアウトするパターン(コメントドキュメント向け)
 *   ・選択範囲内の最小の字下げ位置にあわせる。
 *   ・基本的に「JS アンコメント」してもレイアウトを保持できるが、
 *     各行の字下げルールが同じである前提なので、半角スペースもタブコードも1文字として数える。
 *   ・空白文字だけの行は空行と見做し、行頭記号 " * " を付けた後ろに空白文字を残さない。
 */
function CommentOutJS( str, p1, p2, ast ) {
  var a = str.split( "\n" );
  var b = [];

  // 各行の字下げ数からの最小値を取得
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    var id = a[i].search( /[^ \t]/ );	// 字下げの空白文字数を取得(空白行では -1)
    b.push( id < 0 ? 100000 : id );	// ※ -1 は sort のジャマなのでデタラメな数値に置きかえる
  }
  // 配列 b を昇順で並びかえ(先頭行から最小の字下げ部分の「空白文字 ␣␣ 」を取得)
  b.sort( function( a, b ) { return ( a < b ) ? -1 : ( a > b ) ? 1 : 0; } );
  var blanc = a[0].slice( 0, b[0] );

  // 字下げ位置に中間行の行頭記号 " * " を追加
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    if ( /^[ \t]*$/.test( a[i] ) ) { a[i] = blanc + ast; }	// 空白行
    else { a[i] = blanc + ast + a[i].slice( b[0] ); }
  }

  var prefix = blanc + p1 + "\n";	// 接頭辞
  var suffix = "\n" + blanc + p2;	// 接尾辞
  return prefix + a.join( "\n" ) + suffix;
}

/**
 * 関数 DeleteComment( arg1, arg2 )
 *
 * 複数のコメントブロックが選択範囲内にある場合、最初のコメントブロックしかアンコメントしない
 * 引数 arg2 は 配列[ "接頭辞" , "接尾辞" , "中間行の行頭記号" ] で、
 *   各要素はあらかじめ JavaScript の正規表現で記述されていないとダメ
 *   arg2 = p = [ "\\/\\*+ ?" , " ?\\*\\/" , " ?(\\*|[・・]) ?" ];
 */
function DeleteComment( str, p ) {
  var a = str.split( "\n" ), len = a.length;
  var hit = false, line0 = 0, line1 = len;

  // コメントの接尾辞と接尾辞を検索・置換する
  for ( var j = 0, reg1; j < 2; j ++ ) {
    // 接頭辞 p[0], 接尾辞 p[1] の検索用
    reg1 = new RegExp( p[j], "" );

    for ( var i = 0; i < len; i ++ ) {
      if ( reg1.test( a[i] ) ) {
        a[i] = a[i].replace( reg1, "" );
        // 接頭辞 p[0] がヒットした行
        if ( j == 0 ) { line0 = i;  hit = true;  break; }
        // 接尾辞 p[1] がヒットした行
        else { line1 = i;  break; }
      }
    }
  }

  // 中間行の行頭記号 p[2] (アスタリスク、中黒)を検索・削除
  // 行頭空白文字の後ろの2文字までを置換対象にする
  var reg2 = new RegExp( "^[ \\t]*" + p[2], "" );	// 行頭空白+行頭記号の検索用
  var reg3 = new RegExp( p[2], "" );	// 行頭記号の置換(削除)用

  // 接頭辞(よりも前)の行と接尾辞(よりも後ろ)の行は、検索・置換の対象外
  for ( var i = line0, limit = Math.min( len, line1 ), id, a1, a2;
  i < limit; i ++ ) {
    // 行頭記号がヒットしたら
    if ( reg2.test( a[i] ) ) {
      // 置換範囲(空白文字数+2文字)
      id = a[i].indexOf( a[i].match( /[^ \t]/ ) ) + 2;
      a1 = a[i].slice( 0, id ).replace( reg3, "" );
      a2 = a[i].slice( id );
      a[i] = a1 + a2;
    }
  }

  // 各行の行末空白文字と、先頭/末尾の空行を削除
  return a.join( "\n" )
          .replace( /[\t  ]*$/gm, "" )	
          .replace( /^[\s ]*\n|\n[\s ]*$/g, "" );
}

/**
 * 関数 GetTag( tagType, tagKey, property )
 * 指定された Tag の値を返す
 */
function GetTag( tagType, tagKey, property ) {
  try {
    var obj = ( typeof tagType === "object" ) ? tagType
            : ( tagType === 1 ) ? editor.ActiveDocument
            : ( tagType === 2 ) ? editor
            : ( tagType === 3 ) ? window
            : window;
    return ( obj.Tag.Exists( tagKey )
    && ( property ? property in obj.Tag( tagKey ) : true ) )
    ? property
      ? obj.Tag( tagKey )[ property ]
      : obj.Tag( tagKey )
    : null;
  } catch( e ) { Status = e;  return null; }
}

/**
 * 関数 SetTag( value, tagType, tagKey, property )
 * 指定された値を Tag に書き込む
 */
function SetTag( value, tagType, tagKey, property ) {
  try {
    var obj = ( typeof tagType === "object" ) ? tagType
            : ( tagType === 1 ) ? editor.ActiveDocument
            : ( tagType === 2 ) ? editor
            : ( tagType === 3 ) ? window
            : window;
    if ( property ) {
      if ( obj.Tag.Exists( tagKey ) ) {
        obj.Tag( tagKey )[ property ] = value;
      }
      else { obj.Tag( tagKey ) = { property: value }; }
    }
    else { obj.Tag( tagKey ) = value; }
  }
  catch( e ) { Status = e; }
  finally { return; }
}

/**
 * 関数 AddStrPrompt( tagType, tagKey )
 * 「任意の文字列」コマンド
 * 入力ダイアログで指定された文字列を返す
 */
function AddStrPrompt( tagType, tagKey ) {
  // 前回使用した文字列があればダイアログの初期値に再利用
  var str = "";
  if ( tagType && ( t = GetTag( tagType, tagKey, "addStr" ) ) ) {
    str = t;
  }
  // 入力ダイアログ
  var msg = "につける文字列:\t"
          + "改行 = \\\\\\n ; タブ = \\\\\\t  (注:¥記号3つ)";
  p = Prompt( "前" + msg, str ).replace( /\\\\\\t/g, "\t" )
                               .replace( /\\\\\\n/g, "\n" );
  if ( p && tagType ) {
    SetTag( p.replace( /\t/g, "\\\\\\t" ).replace( /\n/g, "\\\\\\n" )
    , tagType, tagKey, "addStr" );
  }
  return p;
}

/**
 * 関数 DelStrPrompt( tagType, tagKey )
 * 「任意の文字列を削除」コマンド
 * 入力ダイアログで指定された文字列を返す
 */
function DelStrPrompt( tagType, tagKey ) {
  // 前回使用した文字列があればダイアログの初期値に再利用
  var str = "";
  if ( tagType && ( t = GetTag( tagType, tagKey, "delStr" ) ) ) {
    str = t;
  }
  // 入力ダイアログ
  var msg = "から削除する文字列:\t"
          + "タブ = \\\\\\t  (注:¥記号3つ)";
  p = Prompt( "先頭(行頭)" + msg, str ).replace( /\\\\\\t/g, "\t" );
  if ( p && tagType ) {
    SetTag( p.replace( /\t/g, "\\\\\\t" ), tagType, tagKey, "delStr" );
  }
  return p;
}

/**
 * 関数 ToHalfWidth( strVal )
 * 全角英数記号を半角変換して返す
 */
function ToHalfWidth( strVal ){
  // 半角変換(文字コードをシフト)
  return strVal.replace( /[!-~]/g, function( tmpStr ) {
    return String.fromCharCode( tmpStr.charCodeAt(0) - 0xFEE0 );
  } );
}

/**
 * 関数 DelByNumPrompt()
 * 「任意の文字数を削除」コマンド
 * 入力ダイアログで指定された文字列から
 * 数字を抽出して半角数字にして返す
 */
function DelByNumPrompt() {
  var msg = "から削除する文字数 (数字のみ有効):";
  return ToHalfWidth( Prompt( "先頭(行頭)" + msg, "" )
         ).replace( /\D/g , "" );	// 半角に変換して数字以外の文字は削除
}


/**
 * 関数 MultiFunction( Fn, arg1 )
 * マルチカーソル(複数選択範囲)に対応させる
 * 第1引数: Function; 選択範囲ごとに適用する処理の関数
 * 第2引数以降: Function に渡す引数をまとめた配列
 */
function MultiFunction( Fn, arg ) {
  var d = editor.ActiveDocument;
  var s = d.selection;

  // 矩形選択範囲は行に分ける
  s.Mode = meModeMulti;

  // 選択範囲の座標を取得
  var sCount = s.Count;
  var Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = {
      act: s.GetActivePos( i ),
      anc: s.GetAnchorPos( i )
    };
  }

  // 各選択範囲を処理
  for ( var i = 0, diff = 0, dl; i < sCount; i ++ ) {
    dl = d.TextLength;
    s.SetActivePos( Sel[i].act + diff );
    s.SetAnchorPos( Sel[i].anc + diff );

    Fn( arg );	// LineCommentQuote_Main() 関数

    // Fn() の残した選択範囲(またはキャレット位置)を回収
    Sel[i].act = s.GetActivePos();
    Sel[i].anc = s.GetAnchorPos();
    diff += d.TextLength - dl;	// 文字数の増減量(累積)
  }

  // マルチカーソル(複数選択範囲)を復帰
  for ( var i = 0; i < sCount; i ++ ) {
    s.AddPos( Sel[i].anc, Sel[i].act );
  }
}

謝辞[編集]

Kuro 氏の「引用の追加」マクロは Mery のマクロの勉強をはじめたきっかけになったマクロです。

文字列操作、ポップアップメニューの使い方、JavaScript の配列や関数の使い方、if 文、switch 文、for 文、etc... 入門者の "とっかかり" として最適なマクロだったとおもいます(※もとの「引用の追加」は、このページのものよりもシンプル&コンパクトなマクロでした)。

たいへん有用なマクロを作ってくださった Kuro 氏に感謝申し上げます。

残念ながら「引用の追加」マクロは公開停止になってしまいましたので、この度わたしの手元でカスタマイズしたものを公開させていただきました。

改訂版の公開について承諾していただいた Kuro 氏に重ねて御礼申し上げます。 (sukemaru)

スポンサーリンク