カッコで囲う

提供:MeryWiki
2020年6月3日 (水) 18:52時点におけるSukemaru (トーク | 投稿記録)による版 (修正と更新)
ナビゲーションに移動 検索に移動

ダウンロード

全部入りの書庫をダウンロード → 「ファイル:カッコで囲う.zip(アイコン入り)」 (最終更新 2020/06/03)

ZIP 書庫には以下のマクロの JS ファイルと、それぞれ専用の "マテリアルデザインっぽい" アイコンがふくまれています。



カッコで囲う ポップアップメニュー.png


カッコで囲う(ポップアップメニューあり)

(最終更新 2020/06/03)

ポップアップメニューから任意の カッコダッシュ などの種類を選択して、選択範囲をカッコやいろいろな記号、文字列で囲います。
選択範囲がないばあい、基本的にはカーソル位置に ( ), < >, [ ], { }, 「 」, … などを挿入します。

行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで末尾改行が含まれているばあい、さいごの改行を無視します。

  • 既存のポップアップメニュー項目を減らしたいばあいは、ソースコード内の "m.Add( … );" の行頭に // をつけてコメントアウトするとその項目をメニューから隠せます。
  • メニュー項目を増やしたいばあいは、
  1. ソースコード冒頭の配列 p1, p2 の21番目~30番目に任意の , "記号" を追加する
  2. 対応する番号をつけて "m.Add( "カッコ・記号 の名前" , XX );" の行を追加する
  3. 対応する番号をつけて "case XX:" を適当なグループに追加する


作成にあたり、「引用の追加」マクロとキーアサイン集の「括弧で挟む」マクロのコードを参考にしました(※「引用の追加」マクロは 2018/10/14 付けで公開停止になりました)。


姉妹版として 「カッコをはずす」、「カッコを削除/追加」、「カッコを追加/削除」マクロ、「引用符/コメント」マクロがあります。


メニューの項目

任意の文字列で囲う

文字入力用のダイアログで「前につける文字列」と「後ろにつける文字列」を指定します。

  • 任意の文字列1
選択範囲全体を 一組の 指定文字列で前後を囲います。
  • 任意の文字列2
選択範囲内の 各行ごとに 指定文字列で前後を囲います。
ソースコード冒頭の設定項目 skip フラグで、複数行選択のさいに空白行をスキップするか指定してください。
「wiki 文字装飾タグ」以外のカッコ/記号で 各行ごとに囲いたい場合は、「任意の文字列2」を使用してください。

改行コードとタブ文字は、それぞれ「\\\n」と「\\\t」で入力されたもの (注:¥記号3つ) を改行コードとタブ文字に置換するようにしてあります。

※「\n」、「\t」と入力するとそのままの文字列「\n」、「\t」を返します。
※ 文字コードでの入力には非対応です(入力されたままの文字列を返します)。


カッコ/記号 で囲う

選択範囲全体を指定したカッコ/記号で囲います。
選択範囲なしで実行した場合は、カーソル位置にカッコ一組を挿入します。

  •  (半角丸カッコ) 、 <半角山カッコ> 、 [半角角カッコ] 、 {半角波カッコ}、
    (全角丸カッコ) 、 「全角かぎカッコ」 、 『二重かぎカッコ』 、 【スミ付きカッコ】
⇒ 選択範囲をカッコで囲います。
  • ␣(半角丸カッコ)␣ 、 ␣"半角二重引用符"␣
⇒ 選択範囲をカッコまたは引用符で囲い、さらに半角スペースで囲います。
  • ␣半角スペース␣
⇒ 選択範囲を半角スペースで囲います。
  • - 半角ハイフン - 、 ――ダッシュ×2―― 、 ~チルダ~
※ 「半角ハイフン」は、半角ハイフン=マイナス記号 -両側 に各1つずつ半角スペースがつきます(片側で半角3文字分)。
※ このグループにかぎり、選択範囲なしで実行したときは、片側分だけ "-" "――" "~" 記号を挿入します。



●以下の 削除系の各コマンド は、選択範囲がないときにはポップアップメニューに表示されません。

ひとつ削除

  • カッコをはずす」マクロのコードを移植しました。
    選択範囲全体の先頭/末尾 があらかじめ用意された「対になるカッコ・記号」のペアであれば、その一組のペアを削除します。

※ ポップアップメニューの "カッコの追加用の項目" にない多種多様な記号のペアに対応します。
※「カッコをはずす」マクロの "選択範囲の外側 (前と後) にあるカッコの削除" 機能はありません。


任意の 文字列/文字数 を削除

「任意の文字列2」や「wiki用 マークアップ」と同様に、選択範囲内の論理行の 各行頭と行末にたいして 作用します。
※ 選択範囲を "論理行単位" で拡張しないので、先頭行と末行においては行頭/行末ではなく「選択範囲の先頭/末尾」にたいして作用します。

  • 任意の文字数を削除 ではアラビア数字(半角/全角)以外で入力された文字列をすべて無視します。例えば「1a2あ」と入力された場合は、半角数字の「12」として扱います。
  • 任意の文字列を削除 は簡易的な処理コードなので、正規表現を使用できません。
    また、タブ文字の扱いは「任意の文字列2(追加)」の場合とおなじく「\\\t」で入力されたもの (注:¥記号3つ) をタブ文字(\t)として処理します。


先頭/末尾の空白を削除

  • 先頭/末尾から空白を削除
  • 先頭の空白を削除
  • 末尾の空白を削除
⇒ 選択範囲内の論理行の 各行頭と行末にたいして 作用します。
削除対象の空白文字は、「半角スペース」「全角スペース」「タブ文字」の3種です。
インデント(字下げ)の解除や、行末のムダな空白文字の削除に利用できます。

※ 選択範囲を "論理行単位" で拡張しないので、先頭行と末行においては行頭/行末ではなく「選択範囲の先頭/末尾」にたいして作用します。
※ 空白を削除するだけで、「空行を削除する」ものではありません。


n文字ずつ前後を削除

  • 1文字ずつ前後を削除
  • 2文字ずつ前後を削除
  • 3文字ずつ前後を削除
選択範囲全体の先頭/末尾から 指定の文字数ずつ削除します。


  • 1文字ずつ前後を削除(外側)
選択範囲全体の前と後ろの 各1文字を削除します。
※ 選択範囲が先頭行の行頭から始まっている場合や、最終行の行末で終わっている場合は、選択範囲内の先頭または末尾の1文字が削除されます。


JS / XML コメントアウト

3種類の 挿入型コメントアウト のメタ記号で選択範囲の文字列をコメントアウトできます。また、アンコメント用のコマンドでコメントアウト状態を解除できます。

  • /* JavaScript 挿入型コメントアウト1 */
⇒ 選択範囲全体を /* '' */ で囲います。
  • /* *JavaScript コメントアウト2(ブロックコメント) */
/*
​ * (複数行の)選択範囲全体を "/* \n" と "\n */" で囲い、
​ * 範囲内の各行の行頭に " * " を付けます。
​ */
  • <!-- XML 挿入型コメントアウト -->
⇒ 選択範囲全体を <!-- と --> で囲います。


  • JS アンコメント
  • XML アンコメント
⇒ 上の3種のコメントアウトのメタ記号を削除してアンコメントします。

先頭と末尾のコメントマークは選択範囲の両端でなければ削除されません(選択範囲の先頭/末尾に半角スペース×1が付いていても、コメントマークといっしょに削除できます)。
また、選択範囲内に2組以上のコメントがあると、正常にアンコメントできません。

※ "JS アンコメント" は中間行の行頭記号(アスタリスクと全角/半角中黒)とその前後の半角スペースを削除します。これらの行頭記号を使用した箇条書きを範囲選択して実行すると、同様に行頭記号を削除します。

※ プログラミングをしない人には使いみちがないとおもいますので、ZIP のソースでは初期状態でコメントアウトしてあります。


Wiki用 マークアップ

5種類の wiki用 文字列装飾タグ(テキスト整形マークアップ)を挿入できます。

選択範囲内の 各行ごとに 指定のタグで前後を囲います。
ソースコード冒頭の設定項目 skip フラグで、複数行選択のさいに空白行をスキップするか指定してください。

  • 太字
⇒ 選択範囲全体を '''(シングルクオート×3) で囲います。
  • 斜体(Italic)
⇒ 選択範囲全体を ''(シングルクオート×2) で囲います。
  • 下線
⇒ 選択範囲全体を <u> と </u> で囲います。
  • [[内部リンク]]
⇒ 選択範囲全体を [[ と ]] で囲い、[[リンク|ラベル]] 型の 内部リンク にします。
  • <​nowiki>マークアップ回避<​/nowiki>
⇒ 選択範囲全体を <​nowiki> と <​/nowiki> で囲います。


※ wiki用 文字列装飾タグのままでは使いみちがないとおもいますので、HTML タグ <a> </a> などに書き換えてしまうか、ポップアップメニュー項目をコメントアウトしてしまうとよいでしょう(ZIP のソースでは初期状態でコメントアウトしてあります)。


Mery マクロ用

選択範囲の文字列をコピーし、"二重引用符" つきにして、以下の各種の構文で囲います。

※選択文字列のある行の ひとつしたの行 に各構文を挿入します。
※選択範囲が複数行の場合は "+ \n +" でつなぎ合わせます。

  • アウトプット
Outputbar.Writeln( "..." ); の構文にしてアウトプットバーを表示状態にします。
  • アラート
Alert( "..." ); の構文にします。
  • コンファーム
Confirm( "..." ); の構文にします。
  • ステータス
Status = "..."; の構文にします。


※ マクロのプログラミングをしない人には使いみちがないとおもいますので、ZIP のソースでは初期状態でコメントアウトしてあります。


ソースコード

#title = "<カッコ> ..."
#tooltip = "カッコで囲う (ポップアップメニュー)"
// #icon = "brackets(parenthesis)[2].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",255

/**
 * -----------------------------------------------------------------------------
 * カッコで囲う(ポップアップメニュー)
 * sukemaru, 2018/08/24 - 2020/06/03
 * -----------------------------------------------------------------------------
 * (Last modified: 2020/06/03)
 * 	カッコで囲まれた文字列が2つできてしまう不具合を修正
 * 	処理コード内の一部の変数名を変更
 * (2019/03/28)
 * 	「JS コメントアウト/アンコメント」を正規表現置換メソッドに変更
 * 	「任意の 文字数/文字列 を削除」を追加
 * 	「行頭/行末の空白を削除」を追加
 * 	「1文字ずつ前後を削除(外)」を追加
 * 	「ひとつ削除」を追加(「カッコをはずす」マクロから転用)
 * 	「アウトプット/アラート/コンファーム/ステータス」を追加
 * 	「カッコの定義」を使わないコマンドの ID を 1030~ に変更
 * 	 サブメニューを追加してネスト化
 * -----------------------------------------------------------------------------
 *
 * ポップアップメニューからカッコの種類を選択して、選択範囲をカッコで囲う。
 * 公式 wiki のマクロライブラリより「引用の追加」と「括弧で挟む」のコードを参考にした
 *
 * ・複数行の選択範囲で末尾が改行 \n のとき、さいごの改行は除外する。
 * ・非選択時には、それぞれことなる動作をする。
 * 
 * ※ 「任意の文字列」について ※
 * ・「任意の文字列1」は選択範囲全体をひとくくりに、
 *   「任意の文字列2」は選択範囲内の "各行ごと" で個別に、指定した文字列で前後を囲う。
 * ・wiki 文字装飾タグ以外のカッコで "各行ごと" に囲いたい場合は、「任意の文字列2」を使用する。
 * ・文字コードでの入力には非対応(入力されたままの文字列を返す)。
 * ・改行コードとタブ文字は、それぞれ「\\\n」と「\\\t」で入力されたものを置換する。
 *   パスの入力に配慮しただけの簡易的な置換処理なので、「\」を4つ以上かさねた場合を考慮していない。
 * 
 * ※ 「wiki 文字装飾タグ」について ※
 * ・選択範囲内の "各行ごと" で個別に、指定したタグで前後を囲う。
 * ・空行にもマークアップタグを挿入する場合は、skip オプションを無効にすること。
 * 
 * ※ JS/XML コメントアウト と アンコメント について ※
 * ・「カッコで囲う」マクロでは行の中間部分だけをコメントアウトするので、
 *   行単位でコメントアウトするなら「引用の追加」マクロが適する。
 * ・「カッコで囲う」マクロでは行の先頭部分のコメントマークだけにしかマッチしないので、
 *   コメント部分がインデント(字下げ)されている場合も「引用の追加」マクロが適する。
 * ・ほかにも注意事項があるので、該当コード部分の注意書きを参照のこと。
 * 
 * ※ 「ひとつ削除」について ※
 * ・「開きカッコ」「閉じカッコ」の定義とは別に削除用の定義を使用して、
 *   選択範囲の先頭と末尾の1組の「カッコ」を削除する。
 *   各種カッコ、引用符のほかにも各種の記号のペア、半角空白などを削除対象とする。
 * 
 * ※ 削除系のコマンドについて ※
 * ・選択範囲がないときはポップアップメニュー上に表示しない。
 * 
 * -----------------------------------------------------------------------------
 * ※ ポップアップメニューの項目は、m.Add( … ); の不要な行を行をコメントアウトすれば隠せる。
 * (配列から削除する場合は中身だけ消して  ""  として空要素を残しておかないと
 *   メニューや処理コードの ID と一致しなくなる)
 *
 */

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

// ■「任意の文字列2」と、wiki 文字装飾タグで、複数行の選択範囲内の空白行をスキップするか?
var skip = true;	// (true; スキップする / false; スキップしない)


// ■開きカッコ p1 を配列で定義する
var p1 = new Array( "" ,		// 以下 r = 1~10、11~20、21~ の ID 順
  "(" ,  "<" ,  "[" ,  "{" ,  "(" ,  "「" ,  "『" ,  "【" ,  " (" ,  " (" ,
  " \"" ,  " " ,  " - " ,  "――" ,  "~" ,  "'''" ,  "''" ,  "<u>" ,  "[[" , "<nowiki>" ,
  "" , "" , "" , "" , "" );

// ■閉じカッコ p2 を配列で定義する
var p2 = new Array( "" ,		// 以下 1~10、11~20、21~ の ID 順
  ")" ,  ">" ,  "]" ,  "}" ,  ")" ,  "」" ,  "』" ,  "】" ,  ") " ,  ") " ,
  "\" " ,  " " ,  " - " ,  "――" ,  "~" ,  "'''" ,  "''" ,  "</u>" ,  "]]" , "</nowiki>" ,
  "" , "" , "" , "" , "" );

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

var s = editor.ActiveDocument.selection

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

/* 入力 ダイアログ */
m.Add( "任意の文字列 で前後を囲う (&E) ...", 1050 );   	// Enter the custom string(s)
m.Add( "任意の文字列 2 (&E) ...", 1051 );	// 各行ごとに指定文字列で囲う(skip フラグを指定すること)

/* 削除系コマンド */
if ( s.Text ) {					// 選択範囲がないときは表示しない
  m.Add( "", 0, meMenuSeparator );
  m.Add( "▲ ひとつ削除 (&1)", 1038 );
  m.AddPopup( "● 削除 (&T)", sm1 );
    sm1.Add( "  先頭/末尾から任意の 文字列 を削除 (各行) (&Z) ...", 1053 );
    sm1.Add( "  先頭/末尾から任意の 文字数 を削除 (各行) (&X) ...", 1052 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "≫ 先頭/末尾から 空白 を削除 ≪ (各行) (&W)", 1037 );
    sm1.Add( "≫ 先頭の 空白 を削除   (各行) (&T)", 1035 );
    sm1.Add( "  末尾の 空白 を削除 ≪ (各行) (&B)", 1036 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "◀  1文字ずつ 前後を削除  ▶ (外側) (&0)", 1034 );
    sm1.Add( " ▶ &1文字ずつ前後を削除 ◀  (1)", 1031 );
    sm1.Add( " ▶ &2文字ずつ前後を削除 ◀  (2)", 1032 );
    sm1.Add( " ▶ &3文字ずつ前後を削除 ◀  (3)", 1033 );
}

/* カッコ */
m.Add( "", 0, meMenuSeparator );
m.Add( " ( 半角 小カッコ )  (&P)", 1 );		// Parenthesis
m.Add( "", 0, meMenuSeparator );
m.Add( "< 半角 山カッコ > (&A)", 2 );  		// Angle brackets
m.Add( " [ 半角 大カッコ ]  (&B)", 3 );		// square Brackets
m.Add( " { 半角 中カッコ }  (&C)", 4 );		// Curly brackets

m.Add( "", 0, meMenuSeparator );
m.Add( "( 全角 小カッコ ) (&R)", 5 );      	// Round brackets
m.Add( "", 0, meMenuSeparator );
m.Add( "「 全角 かぎカッコ 」 (&K)", 6 );    	// Kakko
m.Add( "『 全角 二重かぎカッコ 』 (&W)", 7 );	// White corner brackets
m.Add( "【 全角 スミ付きカッコ 】 (&L)", 8 );	// Lenticular brackets

m.Add( "", 0, meMenuSeparator );
m.Add( "␣( 全角 小カッコ )␣ (&F)", 9 ); 	// Full width parenthesis (w/ space)
m.Add( "␣ ( 半角 小カッコ ) ␣ (&H)", 10 );	// Half-width parenthesis (w/ space)
m.Add( '␣ "  半角 引用符  " ␣ (&Q)', 11 );	// double-Quotation mark (w/ space)
m.Add( "␣ 半角 スペース ␣ (&S)", 12 );  	// Space

m.Add( "", 0, meMenuSeparator );
m.Add( "  -  半角 ハイフン  -   (&-)", 13 );	// hyphen-minus	 (w/ spaces)
m.Add( "―― 全角 ダッシュ ―― (&D)", 14 );  	// Dash
m.Add( "~ 全角 チルダ ~ (&T)", 15 );        	// Tilde

/* JS コメントアウト / XML コメントアウト */
// m.Add( "", 0, meMenuSeparator );
// m.Add( "/* *  JS コメントアウト 2  */ (&J)", 1041 );	// JavaScript comment out (block comment)
// m.Add( "/*  JS コメントアウト 1  */ (&V)", 1042 );  	// jaVascript comment out
// m.Add( "▲ JS アンコメント (&U)", 1043, grayFlag );	// Uncomment
// m.Add( "", 0, meMenuSeparator );
// m.Add( "<!--  XML コメントアウト  --> (&X)", 1044 ); 	// Xml comment out
// m.Add( "▲ XML アンコメント (&M)", 1045, grayFlag );	// xMl uncomment

/* wiki マークアップ
   このブロックの項目は、複数行を選択しているとき「選択範囲の各行ごとに囲う」処理をおこなう
  (※ skip フラグを指定すること) */ 
// m.Add( "", 0, meMenuSeparator );
// m.AddPopup( "wiki 文字修飾 (&W)", sm2 );
//   sm2.Add( "''' wiki 太字 '''  (&B)", 16 );  	// Bold
//   sm2.Add( "''  wiki 斜体  ''  ( &I )", 17 );	// Italic
//   sm2.Add( "<u> wiki 下線 </u>  (&U)", 18 );   	// Under line	
//   sm2.Add( "[[  wiki リンク  ]]  (&L)", 19 );	// Link
//   sm2.Add( "<nowiki> </nowiki>  (&N)", 20 );      	// Nowiki

/* Mery マクロ用
   以下の項目は、選択範囲の文字列をコピーして、一行下でそれぞれの構文で囲う */ 
// m.Add( "", 0, meMenuSeparator );
// m.AddPopup( "Mery マクロ (&Y)", sm3 );
//   sm3.Add( "アウトプット (&O)", 1060 );		// OutputBar.Writeln( ... )
//   sm3.Add( "アラート (&A)", 1061 );    		// Alert( ... )
//   sm3.Add( "コンファーム (&C)", 1062 );		// Confirm( ... )
//   sm3.Add( "ステータス (&S)", 1063 );  		// Status = ... 

m.Add( "", 0, meMenuSeparator );
m.Add( "キャンセル\t& ", 0 );	// Escキー でキャンセルできるのでアクセラレータなし


// ポップアップメニューを表示
// m.Track(0); ならキャレット位置、m.Track(1); ならカーソル位置にポップアップ
var r = m.Track( mePosMouse = 1 );	// 選択されたメニュー項目のIDを r に格納する

if ( r > 0 ) {
  Redraw = false;

  var anc = s.GetAnchorPos(),  act = s.GetActivePos();
  var tp = ( anc < act ) ? anc : act;	// 選択範囲の先頭位置
  var bp = ( anc < act ) ? act : anc;	// 選択範囲の末尾位置

  // 選択範囲がなければカーソル位置を取得
  if ( s.IsEmpty ) {
    var pos = s.GetActivePos();
  }

  // マクロ実行前の選択範囲の各座標を取得
  var tx = s.GetTopPointX( mePosLogical );
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );

  // 選択範囲の末尾位置を調整(最後の \n を含めない)
  // ※ { 中カッコ } のばあいは末尾の調整をしない
  if ( ! s.IsEmpty && bx == 1 && r != 4 ) {
    s.SetActivePos( bp - 1 );
    s.SetAnchorPos( tp );
  }

  // 選択範囲の文字列を取得
  var st = tmp = s.Text;

  // 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 21:  case 22:  case 23:  case 24:  case 25:
    // カッコ p1 & p2 で囲う
    s.Text = p1[r] + st + p2[r];

    if ( pos ) {	// 選択範囲がなければカーソルをカッコのなかに移動
      s.SetActivePos( pos + p1[r].length );
    }
    else {			// 選択範囲があれば選択範囲を復元
      s.SetAnchorPos( tp );
    }
    break;


  // ハイフン、ダッシュ、チルダ
  case 13:  case 14:  case 15:
    if ( pos ) {	// 選択範囲がなければ片側分 p1 だけ挿入
      s.Text =  p1[r];
    }
    else {			// 選択範囲があればダーシ p1 & p2 で囲う
      s.Text = p1[r] + st + p2[r];
      s.SetAnchorPos( tp );	// 選択範囲を復元
    }
    break;


  // wiki 文字装飾タグ	※ 太字/斜体/下線/<nowiki>
  case 16:  case 17:  case 18:  case 20:
    // 選択範囲内の「各行を囲う」処理をおこなう。
    // 複数行選択で空白行をスキップするかは冒頭の skip フラグで決定する。
    // 選択範囲なしで実行するとタグの間がわかりづらくなるので全角スペースを挿入する。

    if ( pos ) {	// 選択範囲がなければ p1 & p2 と全角スペースを挿入
      s.Text = p1[r] + " " + p2[r];
      s.SetAnchorPos( pos + p1[r].length );			// カーソルをタグのなかに移動
      s.SetActivePos( s.GetAnchorPos() + 1, true );	// 全角スペースを範囲選択
    }
    else {		// 選択範囲があれば各行を p1 & p2 で囲う
      tmp = AddBrackets( st, p1[r], p2[r], pos, skip );
      if ( tmp != st ) {
        s.Text = tmp;
        s.SetAnchorPos( tp );	// 選択範囲を復元
      }
      else {	// テキストに変更なしなら選択範囲の復元だけ
        s.SetActivePos( act );  s.SetAnchorPos( anc );
      }
    }
    break;


  // wiki 文字装飾		※ 内部リンク用タグ	[[リンク|ラベル]]
  case 19:
    // 選択範囲内の「各行を囲う」処理をおこなう。
    // 複数行選択で空白行をスキップするかは冒頭の skip フラグで決定する。

    if ( pos ) {	// 選択範囲がなければ p1 & p2 と " | " を挿入
      s.Text = p1[r] + " | " + p2[r];
      s.SetActivePos( pos + p1[r].length );			// カーソルをカッコの中に移動
      s.SetAnchorPos( s.GetActivePos() + " | ".length );	// カッコの中を範囲選択
    }
    else {		// 選択範囲があれば各行を [[str|str]] に変換
      var tmp = AddWikiLink( st, p1[r], p2[r], pos, skip );
      if ( tmp != st ) {
        s.Text = tmp;
        s.SetActivePos( tp + p1[r].length );	// p1 の後ろにカーソルを移動
      }
      else {	// テキストに変更なしなら選択範囲の復元だけ
        s.SetActivePos( act );  s.SetAnchorPos( anc );
      }
    }
    break;


  // n文字ずつ前後を削除(内)
  case 1031:  case 1032:  case 1033:
    if ( st ) {			// 選択範囲があれば
      // 選択範囲の両端から n 文字ずつ消す
      var n = ( r - 1030 );
      s.Text = st.slice( n, st.length - n );
      s.SetAnchorPos( tp );	// 選択範囲を復元
    }
    break;


  // 1文字ずつ前後を削除(外)
  case 1034:
    s.SetAnchorPos( tp - 1 );			// 選択範囲の先頭側を1文字拡張
    s.SetActivePos( bp + 1, true );		// 選択範囲の末尾側を1文字拡張
    s.Text = s.Text.slice( 1, - 1 );	// 先頭/末尾を1文字ずつ削除
    s.SetAnchorPos( tp - 1 );			// 選択範囲を復帰する
    break;


  // 行頭/行末の空白を削除	※選択範囲を論理行単位に拡張はしない
  case 1035:  case 1036:  case 1037:
    if ( st ) {	// 選択範囲があれば
      tmp = ( r == 1037 ) ? st.replace( /^[\s ]*|[\s ]*$/gm, "" ) :	// 行頭/行末
            ( r == 1035 ) ? st.replace( /^[\s ]*/gm, "" ) :	// 行頭
           /* r == 1036 */  st.replace( /[\s ]*$/gm, "" ) ;	// 行末

      // 選択範囲に指定文字列がなかった場合 undo 履歴を残さない
      if ( tmp != st ) {
        s.Text = tmp;			// 削除完了
        s.SetAnchorPos( tp );	// 選択範囲を復元
      }
    }
    break;


  // ひとつ削除 (※「カッコをはずす」マクロのコードを流用)
  case 1038:
    // 「ひとつ削除」用のカッコの定義
    var brackets = ""
    + "()「」<>[]{}\"\"''()「」『』<>[]{}【】〖〗⦅⦆⦅⦆〚〛〔〕〘〙〈〉《》"
    + "””’’〝〞〝〟‘’“”――~~〜〜  "
    + "++--**\/\/##==%%::::@@@@※※††||……␣␣__"
    + "○○●●□□■■◇◇◆◆▽▽▼▼△△▲▲☆☆★★"
    + "←→→←↑↓↓↑←←→→↑↑↓↓"
    + "¿?¡!‚‘‚’„“„”“„‘‚‹››‹«»»«——‐‐--"
    + "﹁﹂﹃﹄︵︶︿﹀︽︾︹︺︷︸︻︼︗︘";
    var brackets2 = [
      "<b>", "</b>" , "<i>", "</i>" , "<u>", "</u>" , "<s>", "</s>" ,
      "</", ">" , "<", "/>" , "<!-- ", " -->" , "<!--", "-->" , 
      "/** \n", "\n */" , "/** \n", "\n*/" , "/**\n", "\n */" , "/**\n", "\n*/" , 
      "/* \n", "\n */" , "/* \n", "\n*/" , "/*\n", "\n */" , "/*\n", "\n*/" , 
      "/** ", " */" , "/**", " */" , "/* ", " */" , "/*", " */" , 
      "'''''", "'''''" , "'''", "'''" , "''", "''" , "[[", "]]" ,  
      "<nowiki>", "</nowiki>" , "<span>", "</span>" , "<div>", "</div>" , 
      "<pre>", "</pre>" , "<source lang=\"javascript\">", "<\/source>" 
    ];
    brackets = brackets2.concat( brackets.split( "" ) );

    tmp = DeleteBrackets( st, brackets );
    if ( st != tmp ) {
      s.Text = tmp;
      s.SetAnchorPos( tp );	// 選択範囲を復帰する
    }
    else {	// テキストに変更なしなら選択範囲の復元だけ
      s.SetActivePos( act );  s.SetAnchorPos( anc );
    }
    break;


  // /* * JavaScriptコメントアウト 2 */
  case 1041:
/*
*   基本的に1行めが行の先頭から始まることしか想定していないので、
*   あらかじめコメントアウトする文字列は、行単位でまとまったブロックにしておくとよい。
*   選択範囲の先頭/末尾が行の途中にある状態でコメントアウトする場合は、改行を追加する。
*/
    var p1 = ( tx > 1 ) ? "\n/*\n" : "/*\n";		// */
    var p2 = ( document.Text.charAt( bp ) != "\n" ) ? "\n */\n" : "\n */";
    var ast = " * ";
    // 選択範囲の先頭座標が x = 1 でなければ改行させるので選択範囲の復元用座標を調整
    if ( tx > 1 ) { tp ++; }

    // コメントアウト
//    s.Text = CommentOutJS( st, p1, p2, ast );	// コメントアウト(関数バージョン)
    /*  ※ JS コメントアウト の正規表現置換バージョンの検証は不十分 ※ */ 
    s.Text = p1 + st.replace( /^(.*)$/gm, ast + "$1" ) + p2;

    if ( pos ) {	// 選択範囲がなければカーソルをコメント枠のなかに移動
      s.SetActivePos( s.GetActivePos() - p2.length );
    }
    else {			// 選択範囲があれば選択範囲を復元
      s.SetAnchorPos( tp );
    }
    break;


  /* JavaScript コメントアウト 1 */
  // <!-- XML コメントアウト --> 
  case 1042:  case 1044:
    var p1, p2;
    /* JavaScript コメントアウト 1 */
    if ( r == 1042 ) { p1 = " /* ";  p2 = " */ "; }
    // <!-- XML コメントアウト --> 
    else { p1 = " <!-- ";  p2 = " --> "; }

    if ( pos ) {	// 選択範囲がなければコメントマーク p1 & p2 だけ挿入
      s.Text = p1 + p2;
      s.SetActivePos( pos + p1.length );	// カーソルをコメント枠のなかに移動
    }
    else {		// 選択範囲があれば選択範囲 st をコメントアウト
      s.Text = p1 + st + p2;
      s.SetAnchorPos( tp );				// 選択範囲を復元
    }
    break;


  // JS アンコメント:
  // case 1041 と case 1042: の /* JavaScriptコメント */ をアンコメントする。
  // 選択範囲内の各行頭のコメントマーク "/* "  と " * " と " */" のみマッチ。
  // 「カッコで囲う」では行の先頭部分のコメントマークだけにしかマッチしないので、
  // コメント部分がインデントされている場合は「引用符/コメント」マクロのJSアンコメントを使うこと。
/* 
 * ・選択範囲に複数のコメントブロックがある場合を想定していない。
 * ・中間行の行頭記号はアスタリスク「 * 」、全角中黒「・」、半角中黒「・」を削除対象とする。
 *   (行頭記号と前後の半角スペース各1を削除する)
 * ・JSコメントでない箇条書き文で実行した場合も行頭のビュレット「* ・ ・」を削除する。
 */

/* このタイプのコメントにたいしてもアンコメント処理する。 */

  // XML アンコメント:
  // case 1044 の <!-- XMLコメント --> をアンコメントする。
  // 選択範囲の先頭の " <!-- " と 末尾の " --> " のみマッチ。
  // 選択範囲に複数のコメントがあると正常にアンコメントしない。

  case 1043:  case 1045:
    // 選択範囲の先頭と末尾のコメントマークを削除
//    if ( r == 1043 ) {
//      tmp = UnCommentJS( st );		// JS アンコメント(関数バージョン)
//    }
    /*  ※ JS アンコメントの正規表現置換バージョンの検証は不十分 ※ */ 
    if ( r == 1043 ) {			// JS アンコメント(正規表現バージョン)
      tmp = st.replace( /^ ?\/\*+ ?\n?|\n? ?\*+\/ ?$/gm, "" )
             .replace( /^ ?(?:\*+|[・・]) ?/gm, "" );
    }
    else {	// ( r == 1045 )	// XML アンコメント
      tmp = st.replace( /^ ?<!-+ ?| ?-+ *>\ ?$/g, "" );
    }

    // 選択範囲にコメントマークがなかった場合 undo 履歴を残さない
    if ( tmp == st ) {			// テキストに変更なしなら選択範囲の復元だけ
      s.SetActivePos( act );  s.SetAnchorPos( anc );
    }
    else {
      s.Text = tmp;			// アンコメント完了
      s.SetAnchorPos( tp );	// 選択範囲を復元
    }
    break;


  // 任意の文字列を追加	※テキストボックス
  case 1050:  case 1051:
    // 文字コードでの入力には非対応
    // ダイアログのテキスト入力フィールドから文字列を取得
    var msg = "につける文字列:\t改行=\\\\\\n ; タブ=\\\\\\t  (注:¥記号3つ)";
    var p1 = Prompt( "前" + msg, "" )
             .replace( /\\\\\\n/g, "\n" ).replace( /\\\\\\t/g, "\t" );
    var p2 = Prompt( "後ろ" + msg, "" )
             .replace( /\\\\\\n/g, "\n" ).replace( /\\\\\\t/g, "\t" );

    if ( p1 || p2 ) {
      if ( pos ) {	// 選択範囲がなければ p1 & p2 を挿入
        s.Text = p1 + p2;
        s.SetActivePos( pos + p1.length );	// カーソルをカッコのなかに移動
      }
      else {		// 選択範囲があれば
        // 「任意の文字列1」
        if ( r == 1050 ) {
          //  選択範囲全体を p1 & p2 で囲う
          s.Text = p1 + st + p2;
        }
        // 「任意の文字列2」
        else {
          // 選択範囲の各行を p1 & p2 で囲う
          tmp = AddBrackets( st, p1, p2, pos, skip );
          if ( tmp != st ) { s.Text = tmp; }
          // テキストに変更なし
          else { s.SetActivePos( bp ); }
        }
        s.SetAnchorPos( tp );		// 選択範囲を復元
      }
    }
    break;


  // 各行の前後から任意の文字数/文字列を削除	※テキストボックス
  case 1052:  case 1053:
    if ( ! pos ) {		// 選択範囲があれば
      var msg, p1, p2;

      // 「任意の 文字数 を削除」
      if ( r == 1052 ) {
        // ダイアログのテキスト入力フィールドから文字列を取得
        // ※ 半角に変換して数字以外の文字は削除
        msg = "から削除する文字数 (数字のみ有効):";
        p1 = ToHalfWidth( Prompt( "先頭(行頭)" + msg, "" ) )
             .replace( /[^0-9]/g, "" );	
        p2 = ToHalfWidth( Prompt( "末尾(行末)" + msg, "" ) )
             .replace( /[^0-9]/g, "" );
        // 各行の先頭/末尾から指定文字数を削除
        tmp = DeleteCharByNum( st, p1, p2 );
      }

      // 「任意の 文字列 を削除」
      else {
        // ダイアログのテキスト入力フィールドから文字列を取得
        msg = "から削除する文字列:\tタブ = \\\\\\t  (¥記号3つ)";
        p1 = Prompt( "先頭(行頭)" + msg, "" )
             .replace( /\\\\\\t/g, "\t" );
        p2 = Prompt( "末尾(行末)" + msg, "" )
             .replace( /\\\\\\t/g, "\t" );
        // 各行の先頭/末尾の指定文字列を削除
        var reg = new RegExp( "^" + Quote( p1 ) + "|" + Quote( p2 ) + "$", "gm" );
        tmp = st.replace( reg , "" );
      }

      // 選択範囲に指定文字列がなかった場合 undo 履歴を残さない
      if ( tmp != st ) {
        s.Text = tmp;			// 削除完了
        s.SetAnchorPos( tp );	// 選択範囲を復元
      }
    }
    break;


  // アウトプット / アラート / コンファーム / ステータス
  /**
   * 選択範囲の文字列 st をコピーして、1行下に
   * OutputBar.Writeln( "st" );
   * Alert( "st" );
   * Confirm( "st" );
   * Status = "st";
   * の行を追加する
   * → 追加した行の移動は「行を上/下に移動」マクロで
   * → 引用符がジャマなら「引用符で囲う」マクロで除去を…
   */
  case 1060:  case 1061:  case 1062:  case 1063:
    s.SetActivePoint( mePosLogical, 1, by + 1 );
    // 選択範囲が複数行なら +"\n"+ でつなぐ
    tmp = '"' + st.replace( /\n/g, '" + "\\n" + "' ) + '"';
    var sur = ( ( r == 1063 ) ? ";" : " );" ) + "\n";
    s.Text = ( ( r == 1060 ) ? "OutputBar.Writeln( " :
               ( r == 1061 ) ? "Alert( " :
               ( r == 1062 ) ? "Confirm( " :
              /* r == 1063 */  "Status = "
             ) + tmp + sur;
    // カッコの中の文字列を範囲選択する
    s.SetActivePos( s.GetActivePos() - sur.length );
    s.SetAnchorPos( s.GetActivePos() - tmp.length );
    // アウトプットの場合は、アウトプットバーを表示
    if ( r == 1060 ) {
      ScrollY = s.GetActivePointY( mePosView );
      OutputBar.Visible = true;
    }
    break;


  default:
    break;
  }
}
Redraw = true;


// ------------------------------------------------------------
// 関数
// ------------------------------------------------------------

/* 関数 AddBrackets() */
function AddBrackets( str, p1, p2, pos, skip ) {
  var a = str.split( "\n" );	// 選択範囲 st を "\n" で区切って配列 a に
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    // skip = true のときは、空白行をスキップ
    if ( ! pos && skip && /^\s*$/.test( a[i] ) ) {
      continue;
    }
    // 空行にカッコを挿入する場合は全角スペースをはさむ
    var space = ( ( p1.length && p2.length ) && ( pos || ! a[i].length ) )
              ? " " : "" ;
    a[i] = p1 + space + a[i] + p2;	// 各行をカッコ p1 & p2 で囲う
  }
  return a.join( "\n" );
}


/* 関数 AddWikiLink() */
function AddWikiLink( str, p1, p2, pos, skip ) {
  var a = str.split( "\n" );			// 選択範囲 st を "\n" で区切って配列 a に
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    // skip = true のときは、空白行をスキップ
    if ( ! pos && skip && /^\s*$/.test( a[i] ) ) {
      continue;
    }
    // 空行には全角スペースつきではさむ
    var bar = ( pos || ! a[i].length ) ? " | " : "|" ;
    a[i] =  p1 + a[i] + bar + a[i] + p2;	// 各行を [[str|str]] に置換
  }
  return a.join( "\n" );
}


/* 関数 DeleteCharByNum( st, p1, p2 ) */
function DeleteCharByNum( str, p1, p2 ) {
  var a = str.split( "\n" );
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    // 各行の先頭/末尾からの指定文字数を削除
    a[i] = a[i].slice( p1, a[i].length - p2 );
  }
  return a.join( "\n" );
}


/* 関数 DeleteBrackets( str, brackets ) */
// 選択範囲の先頭と末尾から1組のカッコを削除する
function DeleteBrackets( str, brackets ) {
  // ループ処理で「対になるカッコ」と一致するかチェック
  for ( var i = 0, len = brackets.length; i < len; i ++ ) {
    if ( i % 2 == 1 || ! brackets[i].length ) {
      continue;
    }
    var o = brackets[ i ];		// 開きカッコ
    var c = brackets[ i + 1 ];	// 閉じカッコ

    // 選択範囲内の先頭と末尾が「対になるカッコ」のとき
    if ( str.length >= o.length + c.length
    && str.slice( 0, o.length ) == o
    && str.slice( - c.length ) == c ) {
      str = str.slice( o.length, - c.length );	// 先頭/末尾のカッコを削除
      break;
    }
  }	// end for
  return str;
}


/* 関数 quote( str ) */
// ref. 『正規表現 - JavaScript | MDN』
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
function Quote( str ) {
  return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" ); 
};


/**
 * 全角から半角への変革関数 toHalfWidth( strVal )
 * 入力値の英数記号を半角変換して返却
 * [引数]   strVal: 入力値
 * [返却値] String(): 半角変換された文字列
 */
// https://webllica.com/add-comma-as-thousands-separator/ より
function ToHalfWidth( strVal ){
  var halfVal = strVal.replace( /[!-~]/g, function( tmp ) {
    // 文字コードをシフト
    return String.fromCharCode( tmp.charCodeAt(0) - 0xFEE0 );
  } );
  return halfVal;
}


// ----------------------------------------------------------------------------- 
// 以下の2つの関数は破棄してよいかも
// (switch - case 文の中で replace メソッドでの置換処理に変更した)
// -----------------------------------------------------------------------------
/* 
 * 関数 CommentOutJS()
 * このかたちにコメントアウトする
 */
function CommentOutJS( str, p1, p2, ast ) {
  var a = str.split( "\n" );	// 選択範囲 st を "\n" で区切って配列 a に
  for ( var i = 0, len = a.length; i < len; i ++ )
    a[i] = ast + a[i];			// 各行の先頭に " * " を追加する
  // 各行を "\n" で区切って連結し、先頭に "/*\n"、末尾に "\n */" を追加する
  return p1 + a.join( "\n" ) + p2;
}


/* 
 * 関数 UnCommentJS( str ) 
 * 基本的にこのかたちのコメントブロックしか想定していない(インデントには非対応)。
 * また、複数のコメントブロックがある場合を想定していない。
 * 中間行の行頭記号はアスタリスク「*」と中黒「・」「・」を削除対象とする。
 */ 
function UnCommentJS( str ) {
  var re1 = "^ ?\\/\\*+ ?\\n?";		// 先頭行のコメントマークの正規表現
  var re2 = "\\n? ?\\*+\\/ ?$";		// 末行のコメントマークの正規表現
  var reg = new RegExp( re1 + "|" + re2 , "g" );	// 正規表現オブジェクトに変換
  var re3 = /^ ?(\*+|[・・]) ?/;		// 中間行の行頭記号の正規表現
  var a = str.split( "\n" );		// 選択範囲 st を "\n" で区切って配列 a に

  // 中間行の行頭記号を削除する
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    // 先頭行と末行のコメントマークがある行はスキップ
    if ( reg.test( a[i] ) ) { continue; }
    // 中間行の行頭記号を削除
    a[i] = a[i].replace( re3 , "" );
  }

  // 各行を "\n" で区切って連結し、先頭行と末行のコメントマークを削除
  return a.join( "\n" ).replace( reg , "" );
}



カッコで囲う (ポップアップメニューなし)

(最終更新 2020/06/03)

簡易版です。

c.f. 追加と削除ができる機能強化版 → 「引用符を追加/削除

特定の種類のカッコを一発で追加する小マクロはキーアサイン集にもありますが、コードを改変して前後に付ける "カッコ" のかわりに "任意の文字列" を指定するばあいに「折り返し」表示と相性のよくない部分があります。

また、マクロ実行後のカーソル位置を選択範囲なしのときと選択範囲ありのときとで変えたいばあいも、こちらのコードがよいでしょう。

#title = "( カッコ )"
#tooltip = "( カッコ ) で囲う"
// #icon = "brackets(parenthesis).ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",101

// MeryWiki の マクロライブラリ >> キーアサイン集 の「括弧で挟む」を改変
// 選択範囲の前後に任意の文字列(複数文字)を追加するマクロとしても利用できます

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

var pre = "(";		// 前に付ける文字列(開きカッコ)
var sur = ")";		// 後ろに付ける文字列(閉じカッコ)

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


// 選択範囲の各座標を取得
var s = editor.ActiveDocument.selection;
var ax = s.GetTopPointX( mePosLogical );
var ay = s.GetTopPointY( mePosLogical );

// 選択範囲のテキストを取得し、カッコを追加
var st = s.Text;
s.Text = pre + st + sur;

// カーソルを移動、または範囲選択
if ( ! st ) {	
  // 選択範囲なしだったばあい、カッコのあいだにカーソルを移動
  s.SetActivePos( s.GetActivePos() - sur.length );
}
else {
  // 選択範囲があったばあい、カッコを含めて範囲選択
  s.SetAnchorPoint( mePosLogical, ax, ay );
}



引用符を追加/削除

(最終更新 2020/06/03)

カッコで囲う (ポップアップメニューなし)」の機能強化版です。

”引用符” を一発で追加する小マクロは 「マテリアルデザインっぽいアイコンと『小マクロ集』」 の 「”引用符”を追加」 にもありますが、こちらのマクロでは 「引用符(または指定した文字列)で囲う」操作と「囲っている引用符を削除する」操作を トグル できます。
※ 後ろにつける文字列の末尾が "\n" の場合はトグル不可。


選択範囲の外側(前と後ろ)が ”引用符” の場合も、(自動的に検出して)削除することができます。


  • 文字列指定は ”引用符” 以外の カッコHTML タグ などの任意の文字列に変更できます。
  • 選択範囲が複数行(論理行)にまたがっている場合に、選択範囲全体 を一組の ”引用符” で囲うか、選択範囲内の「各行ごと」に ”引用符” で囲うかを選択することもできます。
  • マクロ実行後のカーソル位置を選択範囲なしのときと選択範囲ありのときとで変えたい場合には、数種類のパターンから選択できるようになっています。


カッコの追加/削除トグルの姉妹版マクロとして 「カッコを削除/追加」、「カッコを追加/削除」があります。


ソースコード

#title = "''引用符'' で囲う"
#tooltip = "ダブルクォーテーションで囲う"
// #icon = "quote_4[2].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",100

/**
 * -----------------------------------------------------------------------------
 * "引用符" で囲う
 * sukemaru (2018/10/19 - 2020/06/03)
 * -----------------------------------------------------------------------------
 * (Last modified: 2020/06/03)
 * 	終了後フラグ  endPos = 3  での終了後のカーソル位置を調整
 * 
 * 選択範囲を指定の文字列("引用符")で囲う
 * 選択範囲がすでに "引用符" で囲われていたら引用符ふたつ "" を削除する
 * 選択範囲外側の外側が "引用符" のときも削除可
 * 選択範囲が複数行のとき、さいごの改行はふくめない
 * 
 */

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

var pre = '"';		// 前に付ける文字列
var sur = '"';		// 後に付ける文字列
  /**
   * ■"引用符" の文字列を指定
   *
   * ※ 文字列をダブルクォーテーション "" で囲うなら、中の「 " 」は要エスケープ 「'"'」=> 「"\""」
   * ※ 引用符以外の文字列を指定するなら 「'"'」=> 「"ほげ"」「"ふが"」
   *   ただし、改行 \n を含む文字列は想定していない(カーソル位置の復帰が…)。
   * ※ 片側しか必要ないならいずれかを 「'"'」=> 「""」にしてよいが、実行後のカーソルの復帰位置が…
   */


var deleteOuter = true;
  /**
   *  ■外側削除フラグ 
   *
   * ・false で選択範囲内側の先頭/末尾の文字列 pre / sur のみを削除。
   * ・true で選択範囲外側の前後の文字列 pre / sur も削除対象にする。
   * ※ 「複数行フラグ」の true / false によらず、選択範囲全体の外側が対象。
   */


var multiLine = true;
  /**
   * ■複数行フラグ
   *
   * ・false で選択範囲「全体」の前後に文字列 pre / sur を追加
   * ・true で選択範囲の「各行」ごとに文字列 pre / sur で囲う
   */


var insert = false;
  /**
   * ■挿入フラグ
   *
   * ・false では、選択範囲がないときはマクロを中止する
   *   また、「複数行フラグ」が有効のときに、空行には挿入しない
   *   選択範囲の末尾に空行があった場合、マクロ実行後のカーソルの復帰位置が
   *   「終了後フラグ」の説明どおりにならないことがある
   * ・true では、選択範囲がないときにはカーソル位置に pre / sur を挿入する
   *   また、「複数行フラグ」が有効のときに、空行にも挿入する
   * ※ 「複数行フラグ」が有効 のときは、空白文字だけの行は空行と見做す
   */


var endPos = 5;		// 指定できる値は 0 ~ 5 ( 6 以上の値は 0 と同じ)
  /**
   * ■終了後フラグ 
   *
   * 0. カーソルは "引用符" の後ろへ。  (※範囲選択なし)
   * 1. カーソルは最後の "引用符" の中へ移動する。  (※範囲選択なし)
   * 2. マクロ実行前に範囲選択がなければカーソルは最後の "引用符" の中へ。  (※要 「挿入フラグ」 = true)
   *    あれば "引用符" の後ろへ移動する。  (※範囲選択なし)
   * 3. マクロ実行前に範囲選択がなければカーソルは最後の "引用符" の中へ移動。  (※範囲選択なし)、
   *    あれば "引用符" を含めた全体を選択範囲にする。  (※カーソルは選択範囲の後ろへ) 
   * 4. "引用符" を含めた全体を選択範囲にする。  (※カーソルは選択範囲の後ろへ) 
   * 5. "引用符" を含めた全体を選択範囲にする。  (※カーソル位置はマクロ実行前の側(先頭 or 末尾)へ)
   * 
   *   ※ "引用符" を含めた選択範囲を残すようにすると、
   *     連続実行で 追加 <=> 削除 のトグルができる。( 3 ~ 5 )
   *     ただし、後に付ける文字列の末尾が "\n" の場合、連続実行での 追加 <=> 削除 のトグルはできない。
   *   ※ "マクロ実行前に範囲選択がなければ~" は「挿入フラグ」が有効のときだけ。
   *   ※ 選択範囲を残す場合、マクロ実行前の選択範囲末尾に改行 \n を含んでいたときには
   *   ※ 「複数フラグ」が有効のとき、 "引用符" の中へ移動する「0 と 1」は適さないとおもわれる。
   *   ※ "範囲選択なし" になる「終了後フラグ」で "引用符" を削除したとき、
   *      カーソルの復帰位置は上の説明どおりにはならないことがある。
   */

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


var d = editor.ActiveDocument,  s = d.selection;

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
  // Quit();
}
// 挿入フラグが無効 ( insert = false ) で 選択範囲がないなら中止
else if ( ! insert && s.IsEmpty ) {
  Status = " 選択範囲がありません。";
  // Quit();
}

// 選択範囲がある または 挿入フラグが有効 ( s.length || insert = true ) なら ~
else {
  Redraw = false;

  var delCount = 0;		// 削除フラグ
  var addCount = 0;		// 追加フラグ
  var isAdjusted = false;	// 末尾調整フラグ

  // 選択範囲の各座標
  var anc = s.GetAnchorPos();
  var act = s.GetActivePos();
  var tp = ( anc < act ) ? anc : act;	// 選択範囲の先頭位置
  var bp = ( anc < act ) ? act : anc;	// 選択範囲の末尾位置
  // var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );

  // 選択範囲の末尾が行頭 x = 1 にあるときの調整(末尾の改行を含めない)
  if ( tp < bp && bx == 1 ) {
    s.SetActivePos( tp );
    s.SetAnchorPos( bp - 1 );
    isAdjusted = true;
  }

  // 選択範囲の文字列を取得
  var st = s.Text;

  // 外側フラグが有効のとき
  if ( deleteOuter ) {
    // 選択範囲外側の前後の文字列が "引用符" なら削除する
    // ※削除したときの戻り値は delCount = 1
    delCount = DeleteOuterBrackets( st, pre, sur );
  }

  // AddDelBrackets() で "引用符" を追加/削除
  if ( ! delCount ) {
    var ad = AddDelBrackets( st, pre, sur );
    if ( delCount || addCount ) {
      s.Text = ad;
    }
    // AddDelBrackets() 処理の前後で文字列に変化がないなら
    // 選択範囲を復帰する(undo 履歴を残さない)
    else {
      s.SetActivePos( act );
      s.SetAnchorPos( anc );
      // Quit();
    }
  }

  if ( s.IsEmpty ) {
    // カーソルは "引用符" のうしろ
    var dp = s.GetActivePos();
    // 終了後フラグの指定動作  ※カーソルを移動/選択範囲を復旧
    FinalSelection();	
  }

  Redraw = true;
}

// ---------- ▼ 関数 ▼ ----------

/**
 * 関数 FinalSelection() 
 *   終了後フラグの指定動作  ※カーソルを移動/選択範囲を復旧
 *   0. カーソルは "引用符" の後ろへ。  (※範囲選択なし)
 *   1. カーソルは最後の "引用符" の中へ移動する。  (※範囲選択なし)
 *   2. マクロ実行前に範囲選択がなければカーソルは最後の "引用符" の中へ。  (※要 挿入フラグ = true)
 *   あれば "引用符" の後ろへ移動する。  (※範囲選択なし)
 *   3. マクロ実行前に範囲選択がなければカーソルは最後の "引用符" の中へ移動。  (※範囲選択なし)、
 *   あれば "引用符" を含めた全体を選択範囲にする。  (※カーソルは選択範囲の後ろへ) 
 *   4. "引用符" を含めた全体を選択範囲にする。  (※カーソルは選択範囲の後ろへ) 
 *   5. "引用符" を含めた全体を選択範囲にする。  (※カーソル位置はマクロ実行前の側(先頭 or 末尾)へ)
 */
function FinalSelection() {
  // 0. カーソルは "引用符" のうしろ 
  // ※範囲選択なし(末尾調整されたままの位置)
  switch ( endPos ) {

  // 1. カーソルは "引用符" の中へ移動する  ※範囲選択なし
  case 1:
    SearchCloseBracket ();
    break;

  // 2. マクロ実行前に範囲選択がなければカーソルは "引用符" の中へ
  //    あれば選択範囲の後ろへ移動する  ※範囲選択なし
  case 2:
    // マクロ実行前に選択範囲がなかったとき → case 1 と同じ
    if ( ! st ) {
      SearchCloseBracket();
    }
    break;

  // 3. マクロ実行前に範囲選択がなければカーソルは "引用符" の中へ移動  ※範囲選択なし
  //    あれば "引用符" を含めた全体を選択範囲にする  ※カーソルは選択範囲の後ろへ
  case 3:
    // マクロ実行前に選択範囲がなかったとき → case 1 と同じ
    if ( ! st ) {
      SearchCloseBracket();
    }
    // マクロ実行前に選択範囲があったとき → case 2 と同じ
    else {
      MoveToEndPos();
      s.SetAnchorPos( tp );	// 先頭まで範囲選択
    }
    break;

  // 4. "引用符" を含めた全体を選択範囲にする 
  // ※カーソルは選択範囲の後ろへ(末尾位置を復帰)
  case 4:
    MoveToEndPos();
    s.SetAnchorPos( tp );
    break;

  // 5. "引用符" を含めた全体を選択範囲にする(末尾位置を復帰)
  // ※カーソル位置はマクロ実行前の側(先頭 or 末尾)へ
  case 5:
    MoveToEndPos();
    // マクロ実行前のキャレットの位置が末尾だったとき
    if ( anc <= act ) {
      s.SetAnchorPos( tp );
    }
    // マクロ実行前のキャレットの位置が先頭だったとき
    else {	
      s.SetActivePos( tp, true );
    }
    break;

  default:
    break;
  }
}


/* 関数 AddDelBrackets() */ 
function AddDelBrackets( str, o, c ) {

  // ■複数行フラグ ( multiLine ) にしたがい選択範囲 st を配列 a に
  var a = ( multiLine ) ? str.split( "\n" ) : [ str ];

  for ( var i = 0, len = a.length; i < len; i ++ ) {

    // 選択範囲がカッコで囲われているときは、各行のカッコを削除
    if ( a[i].slice( 0, o.length ) == o
    && a[i].slice( - c.length ) == c ) {
      a[i] = a[i].slice( o.length, a[i].length - c.length );
      delCount ++;	// 削除フラグ
    }
    // 選択範囲がカッコで囲われていないとき
    // 挿入フラグが有効ならカッコをつける
    else if ( insert || /[^\s ]/.test( a[i] ) ) {
      a[i] = o + a[i] + c;
      addCount ++;	// 追加フラグ
    }
    // 挿入フラグが無効のときの空白行はスルー
    else { continue; }
  }

  return a.join( "\n" );
}


/* 関数 DeleteOuterBrackets() */ 
function DeleteOuterBrackets( str, o, c ) {

  // 選択範囲外側の前後の文字列が "引用符" なら削除する
  if ( d.Text.slice( tp - o.length, tp ) == o
  && d.Text.slice( bp, bp + c.length ) == c ) {
    s.SetActivePos( tp - o.length );
    s.SetAnchorPos( bp + c.length );
    s.Text = s.Text.slice( o.length, - c.length );

    tp = tp - o.length;	// 先頭の座標を調整
    delCount ++;
  }
  return delCount;		// 戻り値として削除フラグを返す
}


/* 関数 SearchCloseBracket() */ 
// カーソルを最後の閉じカッコの前へ移動  ※範囲選択なし
function SearchCloseBracket() {
  // カッコを削除したときは、末尾のまま
  if ( delCount ) {
    s.SetActivePos( dp );
  }
  // カッコを追加したときは、選択範囲内の最後の閉じカッコの前へ
  else {
    var Quote = function( str ) {
      return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" ); 
    };
    if ( sur.length || addCount ) {
      s.SetAnchorPos( tp );
      s.SetActivePos( tp + s.Text.lastIndexOf( s.Text.match( Quote( sur ) ) ) );
    }
    // 閉じカッコ sur が未指定 "" の場合は、末尾のまま
  }
}


/* 関数 MoveToEndPos() */ 
// マクロ実行前に選択範囲があったとき、カーソルを元の選択範囲の末尾位置へ移動 
// ※範囲選択なし
function MoveToEndPos() {
  // 選択範囲の末尾調整をしていたときは、カーソルを元の末尾位置に復帰
  if ( isAdjusted ) {
    s.SetActivePoint( mePosLogical, 1, by );
  }
  // 末尾調整をしていなかったときは、カーソル位置はそのまま
  else {
    s.SetActivePos( dp );
  }
}


メモ

JS コメントアウトについて

"/* " と " */" と " * " で複数行のブロックコメントをつくる機能は、
姉妹版の「引用符/コメント」マクロにもあります。

  • 【例】 字下げされた hoge, fuga, piyo の3行をコメントアウトする
          hoge
            fuga
              piyo


  • カッコで囲う(ポップアップメニューあり)」マクロの「JS コメントアウト2」コマンド
    ※ つねに 行の先頭へ コメントマークを挿入します。
    また、行内の一部分を範囲選択して実行した場合は、改行を入れて選択範囲の文字列だけをコメントアウトします。
/*
 *           hoge
 *             fuga
 *               piyo
 */


  • 引用符/コメント」マクロの「JS コメントアウト2」コマンド
    字下げされたブロックの先頭位置へ コメントマークを挿入します。
    また、行内の一部分を範囲選択して実行した場合は、選択範囲を論理行全体に拡張してコメントアウトします。
          /* 
           * hoge
           *   fuga
           *     piyo
           */

※ どちらのマクロの「JS コメントアウト2」コマンドでも、コメントアウトされた各行の文字列の先頭位置は、半角3文字ぶん下がります。
※ どちらのマクロもアンコメント機能がありますが、「カッコで囲う」マクロは、「引用符/コメント」マクロによって "字下げ位置に挿入されたコメントマーク" を正しく削除できません。



※ どちらのマクロも "/* " と " */" だけでコメントアウトすることもできます。

また、"<!--" と "-->" でのコメントアウトとアンコメントもできます。


  • 「カッコで囲う」マクロは選択範囲内を、「引用符/コメント」マクロは選択範囲のある行全体をコメントアウトします。
"hijklmn" の部分を範囲選択してコメントアウトする

abcdefghijklmnopqrstuvwxyz


「カッコで囲う」マクロの場合

abcdefg /* hijklmn */ opqrstuvwxyz
abcdefg <!-- hijklmn --> opqrstuvwxyz


「引用符/コメント」マクロの場合

/* abcdefghijklmnopqrstuvwxyz */
<!-- abcdefghijklmnopqrstuvwxyz -->


GetKeyState.exe の活用

GetKeyState.exe を活用して、「カッコで囲う (ポップアップメニュー)」マクロなら カッコの前後に半角空白をつける、「引用符を追加/削除」マクロなら 引用符ではなく「半角空白を追加/削除」する というようなカスタマイズができるとおもいます。

  • GetKeyState.exe の導入の仕方や使い方、注意事項などについては「GetKeyState.exe(キー状態取得実行ファイル)」のページを参照してください。
  • 以下のサンプルコード(sukemaru 自家用版まま)では Mery インストールフォルダ内の Macros フォルダに GetKeyState.exe を配置している想定です。


「カッコで囲う(ポップアップメニューあり)」のカスタマイズ例

ソースコード内の
// IDごとのテキスト変換処理
の行の に以下のコードを挿入すると、Ctrl キーを押しながらカッコを選択した場合にはカッコの内側に半角空白がひとつずつ追加されます。
「半角空白で囲んでからカッコで囲う」操作が1回でできますし、ソースコードの配列やメニュー項目、case xx: への差分の追加の必要がなくなります。

  // Ctrl キーを押しながらカッコを選択したときは、カッコの内側に半角空白を追加する
  var $Ctrl = function() {
    var gks = editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" );
    return (
    new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks )
    && new ActiveXObject( "WScript.Shell" ).Run( '"' + gks + '" ctrl', 0, true ) === 1
    );
  }
  if ( r < 1030 && $Ctrl() ) {
    p1[r] = p1[r] + " ";	// 開きカッコの後ろに半角空白を追加
    p2[r] = " " + p2[r];	// 閉じカッコの前に半角空白を追加
  }


「引用符を追加/削除」のカスタマイズ例

ソースコード内の
// ---------- ▲ 設定項目 ▲ ----------
の行の に以下のコードを挿入すると、Ctrl キーを押しながら実行した場合には設定項目で指定した 「"引用符" の追加/削除」 ではなく「半角空白を追加/削除」になります。
pre = "hoge"; sur = "fuga"; の部分は1文字ずつではない任意の長さの文字列や記号、HTML タグなども指定できます(改行 "\n" を含む文字列は不可)。

// Ctrl キーを押しながらマクロを実行したときは、引用符ではなく半角空白を追加/削除する
var gks = editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" );
if ( new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks )
&& new ActiveXObject( "WScript.Shell" ).Run( '"' + gks + '" ctrl', 0, true ) === 1 ) {
  pre = " ";	// 半角空白
  sur = " ";	// 半角空白
}


更新履歴

  • 2020/06/03 (sukemaru)
・「カッコで囲う (ポップアップメニューあり)」のカッコで囲まれた文字列が2つできてしまう不具合を修正。
 コード内の変数名などを変更(関数の戻り値を代入する変数名を tmp に統一)
・「引用符を追加/削除」のコードを微修正
document ⇒ editor.ActiveDocument に変更
・「カッコで囲う.zip」を差し替え
  • 2019/04/07 (sukemaru)
・「引用符を追加/削除」から Quit() メソッドを削除
・「カッコで囲う.zip」を差し替え
  • 2019/03/28 (sukemaru)
・「カッコで囲う (ポップアップメニューあり)」のコードを増補・改変。人柱版追加コードを統合。
・「JS コメントアウト/アンコメント」を正規表現置換メソッドに変更
・「任意の 文字数/文字列 を削除」を追加
・「行頭/行末の空白を削除」を追加
・「1文字ずつ前後を削除(外)」を追加
・「ひとつ削除」を追加(「カッコをはずす」マクロから転用)
・「アウトプット/アラート/コンファーム/ステータス」を追加
・「カッコの定義」を使わないコマンドの ID を 1030~ に変更
・ サブメニューを追加してネスト化
・「引用符を追加/削除」に選択範囲の外側の”引用符”の削除機能を追加
・「引用符を追加/削除」の終了時の動作コードを再変更
・「カッコで囲う.zip」を差し替え
  • 2018/10/29 (sukemaru)
・「カッコで囲う (ポップアップメニューあり)」の節を更新(本体のソースコードに追加コードを包摂)
・「カッコで囲う (ポップアップメニューあり)」のメニュー項目に「任意の文字列2」を追加
・「カッコで囲う (ポップアップメニューあり)」のソースコードをまとめてページ下部に移動
・「カッコで囲う.zip」を差し替え
  • 2018/11/19 (sukemaru)
・「カッコで囲う (ポップアップメニューあり)」用の人柱版追加コード「行頭/行末から任意の 文字数 を削除」「行頭/行末から任意の 文字列 を削除」を追加
  • 2018/10/26 (sukemaru)
・コードの体裁を修正 (※変数名を変更したので、追加コードは最新の「カッコで囲う」でないとエラーになる)
・各マクロの動作コードを変更し、実行後の文字列に変化なしになる場合に undo 履歴を残さないようにした
・追加コード「任意の文字列」の項目を追加
・追加コードの「JS コメントアウト1」と「XML コメントアウト」のコードをまとめた
・追加コードの「JS アンコメント」で先頭/末尾のコメントマーク /* */ がある行では中間行の行頭記号を削除しないようにした
・「引用符を追加/削除」の終了後の動作コードを変更し、不自然な位置にキャレットが移動する不具合を修正した
・「カッコで囲う.zip」を差し替え
  • 2018/10/19 (sukemaru)
・「引用符を追加/削除」の節を追加
・「カッコで囲う.zip」を差し替え
  • 2018/10/13 - 2018/10/16 (sukemaru)
・マクロのコードを微修正
・「カッコで囲う.zip」を差し替え
  • 2018/10/12 (sukemaru)
「カッコで囲う (ポップアップメニューあり)」のソースコードに "3文字ずつ前後を削除" を追加
組みこみ用コード「wiki用 文字列装飾」と「挿入型コメントアウト」の節を追加
「カッコで囲う.zip」のダウンロードリンクを追加
  • 2018/08/27 (sukemaru)
・「カッコで囲う (ポップアップメニューあり)」のソースコードを修正
・case1~8 の "s.CharLeft( false, p2[r].length );" を "s.SetActivePos( s.GetActivePos() - p2[r].length );" に変更
  • 2018/08/26 (sukemaru)
「カッコで囲う (ポップアップメニューなし)」の節を追加
  • 2018/08/24 (sukemaru)
ページを新規作成



動作の不具合などがあったらお知らせ下さい。 ◆(sukemaru)

  • (2020.05.22 isari)
いつも愛用させていただいております。「カッコで囲う (ポップアップメニュー)」を素のままで使うと、カッコで囲まれた文字列が2つできてしまう、という不具合があるように見受けられます。
おそらくソースコードの211行目を、すぐ下の if(pos) のブロックに入れ込めば改善するかと思われます。
  • (2020/06/03 sukemaru)
>> isari さん
ご報告ありがとうございます。
2019/04/07 版での 217 行目にあたる行の削除と、その他の軽微な変更を施した更新版をアップロードしました。


スポンサーリンク