マルチカーソル選択範囲の並べ替え

提供: MeryWiki
2020年7月4日 (土) 18:06時点におけるSukemaru (トーク | 投稿記録)による版 (Sukemaru がページ「マルチカーソル選択範囲の並べ替え(昇順/降順トグル)」を「マルチカーソル選択範囲の並べ替え」に移動しました: マクロの名前と動作方式の変更)
ナビゲーションに移動 検索に移動

Mery ver 3.0.1 以降の マルチカーソル/複数選択範囲 を昇順または降順で並べ替えます。

  • 単語のみの選択範囲でも、複数行の選択範囲でも「ひとつの選択範囲」として扱います(各選択範囲の末尾改行の調整はしない)。
  • 矩形選択範囲は行に分けてから並べ替えをおこないます(実行後は矩形選択状態を復帰しない)。
  • 同一論理行内で完結している矩形選択範囲では並べ替えをおこないません(折り返し位置より後ろの文字列は矩形選択範囲内の文字列と見做さない)。
【使用例】
  • 選択範囲が2つなら、選択範囲を入れ替え(トグル)
"HOGE" , "FUGA" , "PIYO" ⇒ "FUGA" , "PIYO" , "HOGE" ⇒ "HOGE" , "FUGA" , "PIYO"


  • 選択範囲が3つ以上なら、昇順/降順で並べ替え(トグル)
"HOGE" , "FUGA" , "PIYO" ⇒ "FUGA" , "HOGE" , "PIYO" ⇒ "PIYO" , "HOGE" , "FUGA"
※ 元の並び順に戻すばあいは UNDO (Ctrl+Z) 連打で。


ダウンロード

ファイル:選択範囲の並べ替え.zip

※ 「上/下」「左/右」の矢印アイコンを7つ入れてあります。
  お好みで選んでご利用ください。


ソースコード

#title = "選択範囲の並べ替え(昇順/降順トグル)"
#tooltip = "マルチカーソル選択範囲の並べ替え(昇順/降順)または入れ替え"
// #icon = "arrows_swap_horaizontal[7].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",332

/**
 * ---------------------------------------------------------
 * 「選択範囲の並べ替え(昇順/降順トグル)」
 * sukemaru, 2020/06/29 - 2020/06/30
 * ---------------------------------------------------------
 * マルチカーソル選択範囲を 昇順/降順 で並べ替える(トグル変換)
 * 選択範囲が2つなら入れ替え
 * 
 * 【仕様上の制限】
 * ・動作要件:Mery ver 3.0.1 以降
 * ・矩形選択範囲は行に分けて並べ替える ⇒ 実行後は複数選択状態になる
 * (※ 元の矩形選択のかたちが歪だった場合に、矩形で復帰できないため)
 * ・選択範囲復帰後の各キャレット位置は、各選択範囲の先頭
 * (※ 行単位で並べ替えたときに、キャレットが末尾だと分かりづらい)
 * ・各選択範囲末尾改行の調整なし
 * ・ブックマークを考慮しない
 * ・ゼロ幅選択範囲があるときは並べ替えない
 */

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

// ■ 半角数字を数値で評価してソート
// (各選択範囲内の最初の半角数字部分を数値として扱う ...たぶん小数も可)
var sortByNum = true;

  /**
   * true: 数値順
   * 	1  <  002  <  3  <  10  <  020
   * 	-2.5  <  -2  <  -1  <  0  <  1  <  1.2  <  1.2.30  <  1.2.4
   * 
   * false: 文字順 @ unicode
   * 	002  <  020  <  1  <  10  <  3
   * 	-1  <  -2  <  -2.5  <  0  <  1  <  1.2  <  1.2.30  <  1.2.4
   * 
   * ※ true の場合でも「1.2.30」や「1.2.4」などは
   *    「1.2」までを数値(小数)として評価し
   *    それ以降の「.30」や「.4」は文字列として評価するので
   *    ビルド番号や IP アドレスなどは数値順にならない
   *    また「ほげ 1 ふが 2 ぴよ 3」のように2ヵ所以上数字が出現する場合
   *    2つめ以降の数字はすべて文字列として評価する
   */

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


/**
 * 関数 SortByBlock()
 * マルチカーソル複数選択範囲の入れ替え
 * ※ 昇順/降順 で「ブロックの並べ替え」
 */
( function SortByBlock() {
  var d = editor.ActiveDocument;
  var s = d.selection;
  var ty = s.GetTopPointY( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  var sMode = s.Mode;
  if ( d.ReadOnly || ! sMode || sMode === meModeStream
  || ( sMode === meModeBox && ty === by )
  || ( sMode === meModeMulti && ! s.Text ) ) {
    return;
  }
  BeginUndoGroup();
  AddUndo();

  // 各選択範囲の先頭/末尾の座標と文字列を取得
  s.Mode = meModeMulti;
  var dt = d.Text;
  var sCount = s.Count;
  var Sel = [],  Str = [];
  var act, anc, tp, bp;
  for ( var i = 0; i < sCount; i ++ ) {
    act = s.GetActivePos( i );
    anc = s.GetAnchorPos( i );
    tp  = Math.min( act, anc );
    bp  = Math.max( act, anc );
    Sel[i] = { tp: tp,  bp: bp };
    Str[i] = dt.slice( tp, bp );
    if ( act === anc ) { 
      Status = " ゼロ幅選択範囲は禁止";
      return;
    }
  }
  var tmp = Str.toString();

  // 昇順で並べ替え
  $status = " 昇順で並べ替え";
  Str = Str.sort( Sort );

  // すでに昇順だった場合は降順で並べ替え(反転)
  if ( Str.toString() === tmp ) {
    $status = " 降順で並べ替え";
    Str = Str.reverse();
  }

  // 変更なしなら UNDO 履歴を残さない
  if ( Str.toString() === tmp ) {
    EndUndoGroup();
    d.Undo();
    Status = " 並べ替えなし";
    return;
  }

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

    // 並べ替えを適用
    s.Text = Str[i];

    // 復帰用選択範囲の先頭/末尾
    Sel[i].bp = s.GetActivePos();
    Sel[i].tp = Sel[i].bp - Str[i].length;
    // 文字数の増減量(累積)
    diff += d.TextLength - dl;
  }

  // マルチカーソル/複数選択範囲を復帰
  s.SetActivePos( Sel[ sCount - 1 ].tp, true );
  for ( var i = 0; i < sCount; i ++ ) {
    // キャレットは各選択範囲の先頭
    s.AddPos( Sel[i].bp, Sel[i].tp );
  }
  EndUndoGroup();

  Status = ( sCount === 2 ) ? " 選択範囲を入れ替え"
                            : $status;
} )();

/**
 * 関数 Sort( a, b )
 * 昇順で並べ替え
 * 半角数字部分は「数値」または「文字列」で評価
 * ※ sortByNum はグローバルスコープの設定変数
 */
function Sort( a, b ) {
  var reg = /^(.*?)(-?\d+(?:\.\d+)?)/;
  var aa = reg.exec( a ),  a1 = aa ? aa[1] : "";
  var bb = reg.exec( b ),  b1 = bb ? bb[1] : "";
  var a2 = a,  b2 = b;
  if ( sortByNum && aa && bb && a1 === b1 ) {
    a2 = Number( aa[2] );
    b2 = Number( bb[2] );
  }
  return ( a2 !== a && a2 !== b2 ) ? a2 - b2
       : ( a < b ) ? -1
       : ( a > b ) ?  1
       :/* else */    0;
}


メモ

2020/06/30 (sukemaru)

  • 書き替え禁止のタブで選択範囲のみが移動してしまう不具合を修正
  • 同一論理行内の折り返しによる「見かけ上の矩形選択範囲」でのエラー回避処理を追加
  • 移動後のマルチカーソル選択範囲の各キャレット位置を、各選択範囲の先頭に変更
  • 小数と負の数値の処理を変更
  • ゼロ幅選択範囲をふくむ並べ替えの不具合を修正(ゼロ幅選択範囲があるときは並べ替えなし)
※ 現状のコードでは、ゼロ幅選択範囲があると実行後に選択範囲を正常に復帰に復帰できないことや、元の選択範囲周辺の文字列が消えてしまうことがあるため
スポンサーリンク