「行を複製 (複数行可)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
新規作成
 
MSY-07 (トーク | 投稿記録)
バージョンの表記を修正
 
(2人の利用者による、間の5版が非表示)
1行目: 1行目:
選択範囲がないばあいはカーソル位置の論理行を、選択範囲があるばあいは選択範囲をふくむ論理行全体(複数行可)を、下に複製します。
選択範囲がないばあいはカーソル位置の論理行を、選択範囲があるばあいは選択範囲をふくむ論理行全体(複数行可)を、下または上に複製します。


行の途中からべつの行の途中までのような大ざっぱな範囲選択状態から「行の複製」を実行することを想定しています。
* 行の途中からべつの行の途中までのような大ざっぱな範囲選択状態から「行の複製」を実行することを想定しています。
ルーラーの行番号のドラッグでの複数行選択やトリプルクリックでの行選択で末尾改行が含まれているばあい、さいごの改行を無視します。
* ルーラーの行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで、選択範囲の末尾に改行が含まれているばあい、さいごの改行を無視します。
* Mery Ver 3.0.1 以降のマルチカーソル/複数選択に対応します。
: ※ 同一論理行内に複数のキャレットまたは選択範囲がある場合は、その論理行をキャレットまたは選択範囲の数だけ複製します。
: ※ UNDO したときにはマクロ実行前の選択範囲を復帰します(設定項目 <code>preferBookmark</code> の有効/無効に依らない)。


<source lang="javascript">
== ダウンロード ==
「[[ファイル:行を複製.zip]]」(アイコン入り)
 
2020/06/26:マルチカーソル対応
 
== ソースコード ==
<syntaxhighlight lang="javascript">
#title = "行を複製 (複数行可)"
#title = "行を複製 (複数行可)"
#tooltip = "選択範囲(複数行可)の論理行を複製する"
#tooltip = "選択範囲(複数行可)の論理行を複製する"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",222
// 上向きの矢印のアイコンのインデックスは 223
/**
/**
  * 選択範囲を拡張してカーソル行(論理行)を "複製" する (複数行可)
  * ---------------------------------------------------------
*
  * 行を複製 (複数行可)
  * 文書終端の空行 ( ^[EOF] ) を選択範囲の末尾にぶら下げての "複製" はできるが、可否について条件アリ
  * sukemaru, 2018/08/12 - 2020/06/26
  *   選択範囲の確定時点でのキャレットの位置が "選択範囲の先頭にあるか" / "末尾 ( [EOF] マークの直前) にあるか" で判別する
  * ---------------------------------------------------------
  *   文字列または行番号をドラッグ(または"クリック & Shift+クリック")して選択範囲を確定するさいに
  * 2020/06/26: マルチカーソル/複数選択に対応
  *   ・上(左)から下(右)にむけて選択範囲をつくった場合 → 終端の空行 ( ^[EOF] ) を含める
*  ・下(右)から上(左)にむけて選択範囲をつくった場合 → 終端の空行 ( ^[EOF] ) を含めない
*
* 1行だけの複製なら
* document.selection.DuplicateLine();
  */
  */


var s = document.selection
// ---------- ▼ 設定項目 ▼ ----------
 
// ■ 複製後の選択範囲
var duplicateDown = true; // (下の行:true / 上の行:false)


// 選択範囲の各座標を取得
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );


// 選択範囲の末尾が終端の空行 ( ^[EOF] ) にあるときの調整
// ■ 複数行選択のとき、ブックマークを維持するか?
var e = "";
var preferBookmark = true;
if ( bx == 1 && ! document.Text.charAt( s.GetActivePos() ) ) // カーソル位置に文字がないばあいを ^[EOF] と判定する
  e = "\n";


// 選択範囲の末尾が行頭 x = 1 にあるときの調整
  // false ならブックマークは解除されるが、アンドゥしても選択範囲(行単位)を維持する
if ( ty != by && bx == 1 )
  // true  ならアンドゥすると選択範囲が解除されるが、ブックマークを維持する
   var by = by - 1;
   // ※ブックマークは上の行に残す


// 選択範囲の拡張
// ---------- ▲ 設定項目 ▲ ----------
s.SetActivePoint( mePosLogical, 1, by );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );


// 選択範囲に改行を追加して複製
var d = editor.ActiveDocument;
var t = s.Text;
var s = d.selection;
s.Text = t + e + "\n" + t;


// (下に)複製された行全体を範囲選択
if ( d.ReadOnly ) {
if ( e.length ) { // 終端の空行をふくめて複製したばあい
   Status = " ドキュメントは書き換え禁止です。";
  s.SetActivePoint( mePosLogical, 1, by + 2 );
   s.EndOfDocument( true ); // カーソル位置は選択範囲の末尾
}
}
else { // 通常の行の複製のばあい
else {
   s.SetAnchorPos( s.GetActivePos() + 1 );
   var sx = ScrollX,  sy = ScrollY;
   s.SetActivePoint( mePosLogical, 1, by + 1, true ); // カーソル位置は選択範囲の先頭
  var sMode = s.Mode;
  if ( sMode ) {
    BeginUndoGroup();  AddUndo();
   }
 
  // マルチカーソル/複数選択に対応
  var arg = [ duplicateDown, preferBookmark ];
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! sMode || sMode === 1 ) {
    DuplicateLines( arg );
  }
  // 矩形選択または複数選択のとき
  else {
    MultiFunction( DuplicateLines, arg );
  }
 
  if ( sMode ) {
    EndUndoGroup();
  }
  ScrollX = sx;  ScrollY = sy;
}
}
</source>


文書終端の空行を含めているかいないかで「行の複製」マクロ実行後のキャレット(入力カーソル)の位置をかえているのは、連続で「行の複製」を実行するさいに同じ範囲を選択状態にして複製させるための仕様です。
/**
* 関数 DuplicateLines( [ duplicateDown, preferBookmark ] )
* 行を複製 (複数行可)
*/
function DuplicateLines( arg ) {
  var duplicateDown  = arg[0];
  var preferBookmark = arg[1];
 
  var d = editor.ActiveDocument;
  var s = d.selection;
 
  // 選択範囲の各座標を取得
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  var ey = d.GetLines( 0 ); // 文書終端行のY
 
  // 選択範囲の末尾が終端の空行 ( ^[EOF] ) にあるときの調整用
  var eof = ( ty < by && bx == 1 && ! d.Text.charAt( s.GetActivePos() ) )
          ? "\n" : ""; // カーソル位置に文字がないばあいを [EOF] と判定する
 
  // 選択範囲の末尾が行頭にあるときの調整
  if ( ty < by && bx == 1 ) { by --; }
  // 選択範囲の拡張
  s.SetActivePoint( mePosLogical, 1, by )
  s.EndOfLine( false, mePosLogical );
  s.SetAnchorPoint( mePosLogical, 1, ty );
 
  // 選択範囲に改行を追加して複製
  var st = s.Text;
 
  if ( preferBookmark ) {
    s.Collapse( meCollapseEnd );
    s.Text = eof + "\n" + st;
  }
  else {
    s.Text = st + eof + "\n" + st;
  }
 
  // ■下に複製した行全体を範囲選択する
  if ( duplicateDown ) {
    // 終端の空行をふくめて複製した場合 → キャレット位置は選択範囲の末尾
    if ( eof ) {
      s.SetActivePoint( mePosLogical, 1, by + ( eof + "\n" ).length );
      s.EndOfDocument( true );
    }
    // 通常の行の複製の場合 → キャレット位置は選択範囲の先頭
    else {
      s.SetAnchorPos( s.GetActivePos() + 1 );
      s.SetActivePoint( mePosLogical, 1, by + 1, true );
    }
  }
 
  // ■上に複製した行全体を範囲選択
  else {
    // 終端の空行だけを複製した場合 → 範囲選択なし
    if ( ty == ey && ! st ) {
      s.SetActivePos( s.GetActivePos() - 1 );
    }
    // 通常の行の複製の場合 → カーソル位置は選択範囲の末尾
    else {
      s.SetAnchorPoint( mePosLogical, 1, ty );
      s.SetActivePoint( mePosLogical, 1, by + 1, true );
      // 終端の空行をふくめて複製した場合
      if ( eof ) {
        s.SetActivePos( s.GetActivePos() + eof.length, true );
      }
    }
  }
}
 
/**
* 関数 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 ); // DuplicateLines() 関数で行を複製
 
    // 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 );
  }
}
</syntaxhighlight>
 
== メモ ==
* 文書終端の空行(EOF マークのみの行)を含めているかいないかで「行の複製」マクロ実行後のキャレット(入力カーソル)の位置をかえているのは、連続で「行の複製」を実行するさいに同じ範囲を選択状態にして複製させるための仕様です。
 
* 2019/03/28 (sukemaru)
: "上に複製" するためのオプションフラグを追加(デフォルトで "下に複製" )
: 以前のコードでは "ブックマークの位置がズレる" 問題があったので、動作仕様を変更
 
* 2019/05/07 (sukemaru)
: 従来の「アンドゥしたら範囲選択状態が残る」ほうが良いという人もいるかもしれないので、項目設定にオプションを追加しました。「preferBookmark = false」が従来版の動作ですが、複数行で「複製」を実行した場合にはブックマーク設定がズレたり消えたりします。
 
* 2020/06/26 (sukemaru)
: マルチカーソル/複数選択範囲に対応

2024年9月4日 (水) 00:25時点における最新版

選択範囲がないばあいはカーソル位置の論理行を、選択範囲があるばあいは選択範囲をふくむ論理行全体(複数行可)を、下または上に複製します。

  • 行の途中からべつの行の途中までのような大ざっぱな範囲選択状態から「行の複製」を実行することを想定しています。
  • ルーラーの行番号のドラッグでの複数行選択やトリプルクリックでの行選択などで、選択範囲の末尾に改行が含まれているばあい、さいごの改行を無視します。
  • Mery Ver 3.0.1 以降のマルチカーソル/複数選択に対応します。
※ 同一論理行内に複数のキャレットまたは選択範囲がある場合は、その論理行をキャレットまたは選択範囲の数だけ複製します。
※ UNDO したときにはマクロ実行前の選択範囲を復帰します(設定項目 preferBookmark の有効/無効に依らない)。

ダウンロード[編集]

ファイル:行を複製.zip」(アイコン入り)

2020/06/26:マルチカーソル対応

ソースコード[編集]

#title = "行を複製 (複数行可)"
#tooltip = "選択範囲(複数行可)の論理行を複製する"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",222
// 上向きの矢印のアイコンのインデックスは 223

/**
 * ---------------------------------------------------------
 * 行を複製 (複数行可)
 * sukemaru, 2018/08/12 - 2020/06/26
 * ---------------------------------------------------------
 * 2020/06/26: マルチカーソル/複数選択に対応
 */

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

// ■ 複製後の選択範囲
var duplicateDown = true;	// (下の行:true / 上の行:false)


// ■ 複数行選択のとき、ブックマークを維持するか?
var preferBookmark = true;

  // false ならブックマークは解除されるが、アンドゥしても選択範囲(行単位)を維持する
  // true  ならアンドゥすると選択範囲が解除されるが、ブックマークを維持する
  // ※ブックマークは上の行に残す

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

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

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
}
else {
  var sx = ScrollX,  sy = ScrollY;
  var sMode = s.Mode;
  if ( sMode ) {
    BeginUndoGroup();  AddUndo();
  }

  // マルチカーソル/複数選択に対応
  var arg = [ duplicateDown, preferBookmark ];
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! sMode || sMode === 1 ) {
    DuplicateLines( arg );
  }
  // 矩形選択または複数選択のとき
  else {
    MultiFunction( DuplicateLines, arg );
  }

  if ( sMode ) {
    EndUndoGroup();
  }
  ScrollX = sx;  ScrollY = sy;
}

/**
 * 関数 DuplicateLines( [ duplicateDown, preferBookmark ] )
 * 行を複製 (複数行可)
 */
function DuplicateLines( arg ) {
  var duplicateDown  = arg[0];
  var preferBookmark = arg[1];

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

  // 選択範囲の各座標を取得
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  var ey = d.GetLines( 0 );		// 文書終端行のY

  // 選択範囲の末尾が終端の空行 ( ^[EOF] ) にあるときの調整用
  var eof = ( ty < by && bx == 1 && ! d.Text.charAt( s.GetActivePos() ) )
          ? "\n" : "";	// カーソル位置に文字がないばあいを [EOF] と判定する

  // 選択範囲の末尾が行頭にあるときの調整
  if ( ty < by && bx == 1 ) { by --; }
  // 選択範囲の拡張
  s.SetActivePoint( mePosLogical, 1, by )
  s.EndOfLine( false, mePosLogical );
  s.SetAnchorPoint( mePosLogical, 1, ty );

  // 選択範囲に改行を追加して複製
  var st = s.Text;

  if ( preferBookmark ) {
    s.Collapse( meCollapseEnd );
    s.Text = eof + "\n" + st;
  }
  else {
    s.Text = st + eof + "\n" + st;
  }

  // ■下に複製した行全体を範囲選択する
  if ( duplicateDown ) {
    // 終端の空行をふくめて複製した場合 → キャレット位置は選択範囲の末尾
    if ( eof ) {
      s.SetActivePoint( mePosLogical, 1, by + ( eof + "\n" ).length );
      s.EndOfDocument( true );
    }
    // 通常の行の複製の場合 → キャレット位置は選択範囲の先頭
    else {
      s.SetAnchorPos( s.GetActivePos() + 1 );
      s.SetActivePoint( mePosLogical, 1, by + 1, true );
    }
  }

  // ■上に複製した行全体を範囲選択
  else {
    // 終端の空行だけを複製した場合 → 範囲選択なし
    if ( ty == ey && ! st ) {
      s.SetActivePos( s.GetActivePos() - 1 );
    }
    // 通常の行の複製の場合 → カーソル位置は選択範囲の末尾
    else {
      s.SetAnchorPoint( mePosLogical, 1, ty );
      s.SetActivePoint( mePosLogical, 1, by + 1, true );
      // 終端の空行をふくめて複製した場合
      if ( eof ) {
        s.SetActivePos( s.GetActivePos() + eof.length, true );
      }
    }
  }
}

/**
 * 関数 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 );	// DuplicateLines() 関数で行を複製

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

メモ[編集]

  • 文書終端の空行(EOF マークのみの行)を含めているかいないかで「行の複製」マクロ実行後のキャレット(入力カーソル)の位置をかえているのは、連続で「行の複製」を実行するさいに同じ範囲を選択状態にして複製させるための仕様です。
  • 2019/03/28 (sukemaru)
"上に複製" するためのオプションフラグを追加(デフォルトで "下に複製" )
以前のコードでは "ブックマークの位置がズレる" 問題があったので、動作仕様を変更
  • 2019/05/07 (sukemaru)
従来の「アンドゥしたら範囲選択状態が残る」ほうが良いという人もいるかもしれないので、項目設定にオプションを追加しました。「preferBookmark = false」が従来版の動作ですが、複数行で「複製」を実行した場合にはブックマーク設定がズレたり消えたりします。
  • 2020/06/26 (sukemaru)
マルチカーソル/複数選択範囲に対応
スポンサーリンク