カッコで囲う

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

ダウンロード[編集]

ダウンロード >> 「ファイル:カッコで囲う.zip(アイコン入り)」 (最終更新 2020/06/23)

Mery ver 3.0.1 以降のマルチカーソル/複数選択範囲に対応
ZIP 書庫には以下のマクロの JS ファイルと、それぞれ専用の "マテリアルデザインっぽい" アイコンがふくまれています。



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

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

(最終更新 2020/06/23)

ポップアップメニューから任意の カッコダッシュ などの種類を選択して、選択範囲をカッコやいろいろな記号、文字列で囲います。

選択範囲がないばあい、基本的にはカーソル位置に ( ), < >, [ ], { }, 「 」, … などを挿入します。

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

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

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

メニューの項目[編集]

任意の文字列で囲う[編集]

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

  • 任意の文字列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/23
 * -----------------------------------------------------------------------------
 * (Last modified: 2020/06/23)
 * 	マルチカーソル/複数選択範囲に対応
 * 	入力ダイアログを使用する処理を関数化
 * 	カッコの定義配列の変数名を変更(p1 ⇒ pp1, p1 ⇒ pp1)
 * (2020/06/03)
 * 	カッコで囲まれた文字列が2つできてしまう不具合を修正
 * 	処理コード内の一部の変数名を変更
 * -----------------------------------------------------------------------------
 */

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

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

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


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

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

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


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

else {
  var s = editor.ActiveDocument.selection;
  var grayFlag = s.Text ? 0 : meMenuGrayed;

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

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

  /* 削除系コマンド */
  if ( s.Text ) {	// 選択範囲がないときは表示しない
    m.Add( "", 0, meMenuSeparator );
    m.Add( "▲ ひとつ削除 (&1)", 1038 );
    m.AddPopup( "● 削除 (&T)", sm1 = CreatePopupMenu() );
      sm1.Add( "  先頭/末尾から任意の 文字列 を削除 (各行) (&Z) ...", 1052 );
      sm1.Add( "  先頭/末尾から任意の 文字数 を削除 (各行) (&X) ...", 1053 );
      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 = CreatePopupMenu() );
//     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 = CreatePopupMenu() );
//     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 );
}

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


if ( r > 0 ) {
  Redraw = false;

// ---------- ▼ マルチカーソル/複数選択範囲対応 ▼ ---------- //

  var tagKey = "AddBrackets2";
  var p, p1, p2;
  if ( r === 1050 || r === 1051 ) {	// 「任意の文字列を追加」
    p = Brackets2Prompt( tagType, tagKey );
    p1 = p.p1;  p2 = p.p2;
  }
  else if ( r === 1052 ) {			// 「任意の文字列を削除」
    p = DelStrPrompt( tagType, tagKey );
    p1 = p.p1;  p2 = p.p2;
  }
  else if ( r === 1053 ) {			// 「任意の文字数を削除」
    p = DelByNumPrompt();
    p1 = p.p1;  p2 = p.p2;
  }
  else {
    p1 = pp1[r];  p2 = pp2[r];
  }

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

  Redraw = true;
}

/**
 * 関数 function AddBrackets_Main( [ r, p1, p2, skip ] )
 * カッコで囲う(ポップアップメニュー)のメイン処理
 */
function AddBrackets_Main( arg ) {
  var r    = arg[0];
  var p1   = arg[1];
  var p2   = arg[2];
  var skip = arg[3];

  // マクロ実行前の選択範囲の各座標を取得
  var d = editor.ActiveDocument,  s = d.selection;
  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 + st + p2;
    // 選択範囲があれば選択範囲を復元
    if ( st ) { s.SetAnchorPos( tp ); }
    // 選択範囲がなければカーソルをカッコのなかに移動
    else { s.SetActivePos( pos + p1.length ); }
    break;

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

  // wiki 文字装飾タグ	※ 太字/斜体/下線/<nowiki>
  // 選択範囲内の「各行を囲う」処理をおこなう。
  // 複数行選択で空白行をスキップするかは冒頭の skip フラグで決定する。
  // 選択範囲なしで実行するとタグの間がわかりづらくなるので全角スペースを挿入する。
  case 16:  case 17:  case 18:  case 20:
    // 選択範囲があれば各行を p1 & p2 で囲う
    if ( st ) {
      tmp = AddBrackets( st, p1, p2, skip );
      if ( tmp != st ) {
        s.Text = tmp;
        s.SetAnchorPos( tp );	// 選択範囲を復元
      }
      else {	// テキストに変更なしなら選択範囲の復元だけ
        s.SetActivePos( act );  s.SetAnchorPos( anc );
      }
    }
    // 選択範囲がなければ p1 & p2 と全角スペースを挿入
    else {
      s.Text = p1 + " " + p2;
      s.SetAnchorPos( pos + p1.length );			// カーソルをタグのなかに移動
      s.SetActivePos( s.GetAnchorPos() + 1, true );	// 全角スペースを範囲選択
    }
    break;

  // wiki 文字装飾		※ 内部リンク用タグ	[[リンク|ラベル]]
  // 選択範囲内の「各行を囲う」処理をおこなう。
  // 複数行選択で空白行をスキップするかは冒頭の skip フラグで決定する。
  case 19:
    // 選択範囲があれば各行を [[str|str]] に変換
    if ( st ) {
      var tmp = AddWikiLink( st, p1, p2, skip );
      if ( tmp != st ) {
        s.Text = tmp;
        s.SetActivePos( tp + p1.length );	// p1 の後ろにカーソルを移動
      }
      else {	// テキストに変更なしなら選択範囲の復元だけ
        s.SetActivePos( act );  s.SetAnchorPos( anc );
      }
    }
    // 選択範囲がなければ p1 & p2 と " | " を挿入
    else {
      s.Text = p1 + " | " + p2;
      s.SetActivePos( pos + p1.length );			// カーソルをカッコの中に移動
      s.SetAnchorPos( s.GetActivePos() + " | ".length );	// カッコの中を範囲選択
    }
    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( /^[\t  ]*|[\t  ]*$/gm , "" ) :	// 行頭/行末
            ( r == 1035 ) ? st.replace( /^[\t  ]*/gm , "" ) :	// 行頭
           /* r == 1036 */  st.replace( /[\t  ]*$/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行めが行の先頭から始まることしか想定していないので、
 *   あらかじめコメントアウトする文字列は、行単位でまとまったブロックにしておくとよい。
 *   選択範囲の先頭/末尾が行の途中にある状態でコメントアウトする場合は、改行を追加する。
 */

    p1 = ( tx > 1 ) ? "\n/\*\n" : "/\*\n";
    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 ( st ) { s.SetAnchorPos( tp ); }
    // 選択範囲がなければカーソルをコメント枠のなかに移動
    else { s.SetActivePos( s.GetActivePos() - p2.length ); }
    break;

  /* JavaScript コメントアウト 1 */
  // <!-- XML コメントアウト --> 
  case 1042:  case 1044:
    /* JavaScript コメントアウト 1 */
    if ( r == 1042 ) { p1 = " /\* ";  p2 = " */ "; }
    // <!-- XML コメントアウト --> 
    else { p1 = " <!-- ";  p2 = " --> "; }
    s.Text = p1 + st + p2;
    // 選択範囲があれば選択範囲を復元
    if ( st ) { s.SetAnchorPos( tp ); }
    // 選択範囲がなければカーソルをコメント枠のなかに移動
    else { s.SetActivePos( pos + p1.length ); }
    break;

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

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

  case 1043:  case 1045:
    // 選択範囲の先頭と末尾のコメントマークを削除
//    if ( r == 1043 ) {
//      // JS アンコメント(関数バージョン)
//      tmp = UnCommentJS( st );
//    }
    /*  ※ JS アンコメントの正規表現置換バージョンの検証は不十分 ※ */ 
    // JS アンコメント(正規表現バージョン)
    if ( r == 1043 ) {
      tmp = st.replace( /^ ?\/\*+ ?\n?|\n? ?\*+\/ ?$/gm, "" )
              .replace( /^ ?(?:\*+|[・・]) ?/gm, "" );
    }
    // XML アンコメント
    else {	// ( r == 1045 )
      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:
    if ( p1 || p2 ) {
      if ( st ) {
        // 「任意の文字列1」	選択範囲全体を p1 & p2 で囲う
        if ( r == 1050 ) {
          s.Text = p1 + st + p2;
        }
        // 「任意の文字列2」	選択範囲の各行を p1 & p2 で囲う
        else {
          tmp = AddBrackets( st, p1, p2, skip );
          if ( tmp != st ) { s.Text = tmp; }
          else { s.SetActivePos( bp ); }
        }
        s.SetAnchorPos( tp );	// 選択範囲を復元
      }
      // 選択範囲がなければ p1 & p2 を挿入し、カーソルをカッコのなかに移動
      else {
        s.Text = p1 + p2;
        s.SetActivePos( pos + p1.length );
      }
    }
    break;

  // 各行の前後から任意の文字数/文字列を削除	※テキストボックス
  case 1052:  case 1053:
    if ( st ) {
      // 「任意の文字数を削除」	各行の先頭/末尾から指定文字数を削除
      if ( r == 1053 ) {
        tmp = DeleteCharByNum( st, p1, p2 );
      }
      // 「任意の文字列を削除」	各行の先頭/末尾の指定文字列を削除
      else {	// ( r == 1052 )
        var reg = new RegExp(
          "^" + p1.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" )
        + "|" + p2.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" ) + "$"
        , "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;
  }
}


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


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


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


/**
 * 関数 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; }
}


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


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


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


/**
 * 関数 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 );	// AddBrackets_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 );
  }
}

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

(最終更新 2020/06/23)

簡易版です。

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

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

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

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

/**
 * -----------------------------------------------------------------------------
 * カッコで囲う
 * sukemaru (Last modified: 2020/06/23)
 * -----------------------------------------------------------------------------
 * MeryWiki の マクロライブラリ >> キーアサイン集 の「括弧で挟む」を改変
 * 選択範囲の前後に任意の文字列(複数文字)を追加するマクロとして利用できます
 * 
 * マルチカーソル/複数選択範囲に対応
 */

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

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

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


var s = editor.ActiveDocument.selection;
var sx = ScrollX,  sy = ScrollY;

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


function Brackets_Main( arg ) {
  var pre = arg[0];
  var sur = arg[1];

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

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

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


/**
 * 関数 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 );	// Brackets_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 );
  }
}

引用符を追加/削除[編集]

(最終更新 2020/06/23)

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

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

※ 後ろにつける文字列の末尾が "\n" の場合はトグル不可。

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

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

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

ソースコード[編集]

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

/**
 * -----------------------------------------------------------------------------
 * "引用符" で囲う
 * sukemaru (2018/10/19 - 2020/06/23)
 * -----------------------------------------------------------------------------
 * (Last modified: 2020/06/23)
 * 	マルチカーソル/複数選択範囲に対応
 * (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 = " ドキュメントは書き換え禁止です。";
}

// 挿入フラグが無効 ( insert = false ) で 選択範囲がないなら中止
else if ( ! insert && s.IsEmpty ) {
  Status = " 選択範囲がありません。";
}

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

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


/**
 * 関数 AddDeleteQuote_Main( [ pre, sur, deleteOuter, multiLine, insert, endPos ] )
 * 「引用符を追加/削除」マクロ
 * サブ関数群は適切に引数を設定していないので
 * Main の関数スコープ内に含める
 */
function AddDeleteQuote_Main( arg ) {
  var pre = arg[0];
  var sur = arg[1];
  var deleteOuter = arg[2];
  var multiLine   = arg[3];
  var insert      = arg[4];
  var endPos      = arg[5];

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

  // 選択範囲の各座標
  var d = editor.ActiveDocument,  s = d.selection;
  var anc = s.GetAnchorPos(),  act = s.GetActivePos();
  var tp = Math.min( anc, act );
  var bp = Math.max( anc, act );
  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 tmp = AddDelBrackets( st, pre, sur );
    if ( delCount || addCount ) {
      s.Text = tmp;
    }
    // AddDelBrackets() 処理の前後で文字列に変化がないなら
    // 選択範囲を復帰する(undo 履歴を残さない)
    else {
      s.SetActivePos( act );
      s.SetAnchorPos( anc );
    }
  }

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


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

  /**
   * 関数 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 == tp ) {
        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 );
    }
  }

}


/**
 * 関数 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 );	// AddDeleteQuote_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 );
  }
}

カッコで囲う2(各行ごとにカッコで囲う/Mery ver 3 用)[編集]

選択範囲内(複数選択可)の 各行 (論理行)を、ポップアップメニューから選択したアイテム(カッコ)で囲います。

Mery ver 3.0.1 以降のマルチカーソル/複数選択範囲に対応 。

機能
  • 複数行選択や複数選択(またはマルチカーソル状態)を行に分けたそれぞれの部分をカッコで囲います。
  • 選択範囲がないときはカーソル位置(マルチカーソル可)それぞれにカッコを挿入します。
  • 各選択範囲のさいごの改行は無視しますので、行番号の Ctrl+クリック による複数選択範囲でも使用できます。
制限事項
  • このマクロは Mery ver 2.x では使用できません。
  • 複数行の選択範囲全体を一組のカッコで囲うことはできません。
  • 矩形選択範囲は複数選択範囲に分解します(選択範囲を行に分ける)。
  • カッコの定義配列からポップアップメニューを自動生成する仕様のため、サブメニューを利用したカテゴリ分けはできません。

カッコの登録方法[編集]

ソースコード内の設定項目の配列でカッコの種類を定義します。
カッコで挟みこまれる部分を ... で置きかえた "「...」" が基本形式となります。
設定項目の配列にカッコの定義を追加すると、自動的にポップアップメニュー項目にも追加されるので、「カッコで囲う(ポップアップメニューあり)」マクロよりも簡単にカスタマイズできます。
... がないアイテムはメニューに表示されません。
... を行頭に付加させることはできません。
  • 各行の前後を囲う "カッコ"
カッコや HTML タグ、任意の記号、文字列を "「...」""<pre>...</pre>" のように記述して登録します。
  • 各行の先頭にのみ記号や文字列を付加する場合
">..." のように ... の後ろに文字列をつけずに登録します。箇条書きのビュレットや行頭のコメントマーク、引用符などの挿入に利用できます。
  • 各行の末尾にのみ記号や文字列を付加する場合
"...!?" のように ... の前に文字列をつけずに登録します。
  • ポップアップメニュー先頭の 「任意の文字列...」コマンド を利用すれば、定義配列に登録していないカッコやタグ、記号など任意の文字列を指定することができます。

ソースコード[編集]

#title = "カッコで囲う2"
#tooltip = "選択範囲の各行をカッコで囲う"
#icon = "brackets(parenthesis)[3].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",256

/**
 * ---------------------------------------------------------
 * 「カッコで囲う2」マクロ
 * sukemaru, 2020/06/05 - 2020/06/23
 * rev.1 (2020/06/05): クリップボード経由 ⇒ 2020/06/23 廃止
 * rev.2 (2020/06/23): 選択範囲の復帰可 / MultiFunction() 関数
 * ---------------------------------------------------------
 * Mery ver 3.0.1 以降のマルチカーソル(複数選択範囲)に対応
 * 
 * 選択範囲内(複数選択可)の各行それぞれをカッコで囲います。
 * ※ 選択範囲がないときはカーソル位置(マルチカーソル可)にカッコを挿入します。
 * ※ 各選択範囲の末尾の改行は無視します。
 */


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

// ■ カッコを追加した選択範囲を復帰する
var restoreSel = true;	// (true する / false しない)


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


// ■ カッコ(タグ・記号等の文字列)の種類の定義
// ※ 定義ではカッコの間にドット×3 "..." をはさんでおくこと
// ※ "★..." なら前だけ、"...★" なら後ろだけに文字列をつけられる
// ※ "" でポップアップメニュー内のセパレータ(横罫線)になる
//   ( "..." を含まなければセパレータ)

var pp = [ "",
  "(...)", "[...]", "[[...]]", "(\"...\")", "", 
  "\"...\"", " \"...\" ", "'...'", "", 
  "「...」", "『...』", "【...】", "(...)", "", 
  ">> ...", "> ...", "\/\/ ...", "...\t\/\/ ", "\/\* ... \*\/", "", 
  "※...", "・...", "■...", "◆...◆", "", 
  "''...''", "'''...'''", "<code>...</code>", 
"" ];

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

var tagKey = "AddBrackets2";
var separator = "...";
var spaceChar = "\u2006_\u2006";	// \u2423 ␣

var d = editor.ActiveDocument;
var s = d.selection;
var ac = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var flag = d.ReadOnly ? meMenuGrayed : 0;
var p, p1, p2;
var Split = function( str, sep ) {
  sep = sep.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" );
  return RegExp( "([\\s\\S]*?)" + sep + "([\\s\\S]*)", "" ).exec( str );
}
var Conv = function( str ) {
  return str.replace( /[ ]/g, spaceChar )
            .replace( /\t/g, "\\t" )
            .replace( /\n/g, "\\n" );
};

// ポップアップメニュー
var menu = CreatePopupMenu();
menu.Add( "任意の文字列 (&@) ...", 100000, flag );
// 配列内の要素を追加
for ( var i = j = 0, len = pp.length, label; i < len; i ++ ) {
  // "..." を含まないものはセパレータ
  if ( ! pp[i] || pp[i] === separator
  || String( pp[i] ).indexOf( separator ) === -1 ) {
    menu.Add( "----", 0, meMenuSeparator );
    continue;
  }
  p = Split( pp[i], separator );
  p1 = p[1];  p2 = p[2];
  label = ( ! p1 ) ? Conv( p2 ) + "  を 後ろ に付加"
        : ( ! p2 ) ? Conv( p1 ) + "  を 先頭 に挿入"
        :  Conv( p1 ) + " ・・・ " + Conv( p2 ) + "  で 前後 を囲う";
  if ( ! ac[j] ) { j = 0; }
  label += " (&" + ac[ j ++ ] + ")";
  menu.Add( label, i, flag );
}
menu.Add( "キャンセル	& ", 0 );

if ( flag ) { Status = " ドキュメントは書き換え禁止です。"; }
var r = menu.Track( mePosMouse );

Main2:
if ( r ) {
  if ( r === 100000 ) {	// 「任意の文字列」
    p = Brackets2Prompt( tagType, tagKey );
    p1 = p.p1;  p2 = p.p2;
    if ( ! p1 && ! p2 ) { break Main2; }
  }
  else {
    p = Split( pp[r], separator );
    p1 = p[1];  p2 = p[2];
  }
  var sx = ScrollX,  sy = ScrollY;

  // マルチカーソル/複数選択に対応
  var arg = [ p1, p2, restoreSel ];
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! s.Mode || s.Mode === meModeStream ) {
    AddBrackets2_Main( arg );
  }
  // 矩形選択または複数選択のとき
  else {
    BeginUndoGroup();
    AddUndo();
    MultiFunction( AddBrackets2_Main, arg );
    EndUndoGroup();
  }

  ScrollX = sx;  ScrollY = sy;
}	// Main2: if ( r )


/**
 * 関数 AddBrackets2_Main( [ p1, p2, restoreSel ] )
 * 選択範囲をカッコ p1, p2 で囲う
 * restoreSel は実行後の選択範囲の復帰を指定する真偽値(設定項目)
 */
function AddBrackets2_Main( arg ) {
  var p1 = arg[0];
  var p2 = arg[1];
  var restoreSel = arg[2];

  var d = editor.ActiveDocument;
  var s = d.selection;
  var tp = Math.min( s.GetActivePos(), s.GetAnchorPos() );
  var ty = s.GetTopPointY( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var nl = 0;
  if ( by > ty && bx === 1 ) {
    by --;  nl = 1;
    s.SetActivePoint( mePosLogical, d.GetLine( by, 0 ).length + 1, by );
    s.SetAnchorPos( tp );
  }
  var st = s.Text;

  // カッコを付加した文字列
  var tmp = st.replace( /^.*$/gm, p1 + "$&" + p2 );

  if ( st !== tmp ) {
    // ブックマークを保存
    var bmArray = GetBookmark( ty, by );

    // カッコを付加した文字列を適用
    s.Text = tmp;

    // ブックマークを復元
    RestoreBookmark( ty, by, bmArray );
  }

  s.SetActivePos( tp + tmp.length + nl );
  if ( restoreSel ) {
    s.SetAnchorPos( tp );
  }
}


/**
 * 関数 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; }
}

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


/**
 * 関数 GetBookmark( ty, by )
 * 指定された範囲のブックマークを収集
 */
function GetBookmark( ty, by ) {
  var bmArray = [],  bmY;
  var s = editor.ActiveDocument.selection;
  if ( ty < by ) {
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();

    if ( ty === 1 ) {
      s.SetActivePoint( mePosLogical, 1, 2 );
      if ( s.PreviousBookmark() ) {
        bmY = s.GetActivePointY( mePosLogical );
        if ( bmY >= ty && bmY <= by ) {
          bmArray.push( bmY );
        }
      }
      s.SetActivePos( 0 );
    }
    else { s.SetActivePoint( mePosLogical, 1, ty - 1 ); }

    while ( s.NextBookmark() ) {
      bmY = s.GetActivePointY( mePosLogical );
      if ( bmY >= ty && bmY <= by ) {
        bmArray.push( bmY );
      }
      else if ( bmY > by ) { break; }
    }
    s.SetActivePos( act );  s.SetAnchorPos( anc );
  }
  return bmArray;
}

/**
 * 関数 RestoreBookmark( ty, by, bmArray )
 * 指定された範囲のブックマークを復元
 */
function RestoreBookmark( ty, by, bmArray, sel ) {
  var bmCount = bmArray.length;
  if ( bmCount ) {
    var s = editor.ActiveDocument.selection;
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();
    s.SetActivePoint( mePosLogical, 1, ty );
    s.ClearBookmark();
    for ( var i = 0; i < bmCount, bmArray[i] <= by; i ++ ) {
      if ( bmArray[i] < ty ) { continue; }
      s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
      s.SetBookmark();
    }
    if ( sel ) {
      s.SetActivePos( act );  s.SetAnchorPos( anc );
    }
  }
}


/**
 * 関数 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 );	// AddBrackets2_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 );
  }
}

メモ[編集]

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

マルチカーソル/複数選択範囲への対応[編集]

Mery ver 3.0.1 以降 のマルチカーソル(複数のキャレットを置いた状態)や複数選択範囲のそれぞれにたいして、マクロを連続的に実行します (※ ver 3.0.0 はサポート外)。

  • 「カッコで囲う (ポップアップメニュー あり/なし)」マクロは、基本的にそれぞれの選択範囲ごとに一組のカッコで囲います。
※ 「Wiki用マークアップ」の各コマンドは、選択範囲内の各行ごとに囲います。
※ 「任意の文字列/文字数」系のコマンドでは、1回だけ入力ダイアログが表示され、指定した内容ですべての選択範囲または選択範囲内の各行を処理します。
  • 「引用符を追加/削除」マクロは、設定項目 multiLine の true/false で指定された動作ですべての選択範囲を処理します。
※ "引用符" で囲った文字列と囲っていない文字列をそれぞれ範囲選択して実行すると、"引用符" で囲われた選択範囲では「削除」、囲われていない選択範囲では「追加」の動作をします。
※ 連続実行での「追加/削除」のトグル動作可。
  • 「カッコで囲う2」マクロは、それぞれの選択範囲内の各行ごとにカッコで囲います。
※ 同一論理行内の複数の選択範囲は、それぞれを「ひとつの行」として扱います。
  • Mery ver 3.0.x ~ での矩形選択範囲にたいしては、「選択範囲を行に分け」て、選択範囲内の各行ごとに処理を実行します。
※ 同一論理行内の折り返しにたいしては「選択範囲を行に分ける」処理が正常になされません。
※ Mery ver 2.x での矩形選択範囲にたいしては、正常に処理できません。

更新履歴[編集]

  • 2020/06/23 (sukemaru)
・「カッコで囲う2」を追加(実験カテゴリから移動・統合)
・Mery ver 3.0.x ~ のマルチカーソル/複数選択範囲に対応
・「カッコで囲う (ポップアップメニューあり)」のコードを整理しなおし、定義配列の変数名や、ポップアップメニューの ID などの変更あり。
  • 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)
ページを新規作成



動作の不具合などお気づきの点があったら Mery 公式フォーラム にてお知らせ下さい。 ◆(sukemaru)

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