emacsでライン/リージョンを上下に移動する


85

選択した領域または行(選択がない場合)をemacsで上下に移動する最も簡単な方法は何ですか?Eclipseと同じ機能を探しています(M-up、M-downにバインドされています)。


1
移動したいものを強制終了し、通常のナビゲーション機能(isearchなどを含む)を使用してコードを配置したい場所に移動してから、ヤンクするのがイディオムだと確信しています。キルのスタックがあるので、すぐに場所を見つける必要はありません。後でヤンクするために他のビットを集めることができます。個人的には、Emacsのヘビーユーザーとして、1行を手動で上下に移動したいという状況は想像できません。それは役に立たないでしょう。
jrockway 2010年

7
@jrockway:コメントありがとうございます。誰もが自分のやり方を持っていると思います。私は日食をよく扱い、線/領域の移動に非常に慣れています。emacsを非常に拡張可能にすることの素晴らしい点の1つは、この機能を簡単に追加できることです。
fikovnik 2010年

3
同意した。私は、それをサポートするエディターを使用しているかどうかに関係なく、説明どおりに行を上下に移動したいと思うことがよくあります。または、そのことについては、私がコードに取り組んでいるかどうかにかかわらず。WordはAlt + Shift + UpとDownでこれを(段落ごとに)サポートしており、可能な限りエディターでマップします。
harpo 2010

6
@Drewとjrockway:より少ない金額で解決することはemacsの方法ではないと思います。ラインを移動したい場合は、kill / yankkよりもラインの移動が速くなります。そしてもちろん、org-modeも実装されています。理由は次のとおりです。実際、行を移動したい場合が多く、間違って配置されたステートメントをブロックスコープに出し入れするのは、ステートメントの順序を変更し、ドキュメントの順序を変更することです(org-を参照)。モード)、..多くの人が日食でそれを使用します。使用しないもの、見逃すことはほとんどありませんが、線を移動することの有用性は、多くのプログラマーにとって事実です
Peter

2
これは、並べ替える可能性のあるコミットのリストを含むgit-rebaseファイルを編集するときに役立ちます。
ケンウィリアムズ

回答:


47

にバインドされた転置線を使用して、線を移動できますC-x C-t。しかし、地域については知らない。

バインディングを変更する必要があることを除いて、あなたが望むことをするこのelispスニペットを見つけました。

(defun move-text-internal (arg)
   (cond
    ((and mark-active transient-mark-mode)
     (if (> (point) (mark))
            (exchange-point-and-mark))
     (let ((column (current-column))
              (text (delete-and-extract-region (point) (mark))))
       (forward-line arg)
       (move-to-column column t)
       (set-mark (point))
       (insert text)
       (exchange-point-and-mark)
       (setq deactivate-mark nil)))
    (t
     (beginning-of-line)
     (when (or (> arg 0) (not (bobp)))
       (forward-line)
       (when (or (< arg 0) (not (eobp)))
            (transpose-lines arg))
       (forward-line -1)))))

(defun move-text-down (arg)
   "Move region (transient-mark-mode active) or current line
  arg lines down."
   (interactive "*p")
   (move-text-internal arg))

(defun move-text-up (arg)
   "Move region (transient-mark-mode active) or current line
  arg lines up."
   (interactive "*p")
   (move-text-internal (- arg)))

(global-set-key [\M-\S-up] 'move-text-up)
(global-set-key [\M-\S-down] 'move-text-down)

スニペットをありがとう。これはまさに私が探していたものです!
fikovnik 2010年

この解決策と@sanityincによって投稿されたほぼ同じ解決策の両方に少し問題があります:定義されたショートカットを使用して領域を上下に移動する場合は、すぐに元に戻すためのショートカットを使用します(デフォルトではC-_)、リージョンが消え、「リージョンで元に戻す!」というメッセージが表示されます。エコーエリアにが表示されます。別の元に戻すコマンドは、「リージョンの元に戻す情報はありません」というメッセージを生成します。ただし、カーソルを移動してから「元に戻す」コマンドを実行すると、元に戻す機能が再開されます。比較的軽度の刺激ですが、他のすべてのEmacsコマンドは、トリックに頼ることなくすぐに元に戻すことができます。
Teemu Leisti 2013

1
これはまさに正しい方法です。Emacsのデフォルトの転置行は正しい機能ではありません。これは、転置後にカーソルが次の行に移動し、段階的に繰り返すことが困難になるためです。
mythicalcoder

51

更新:move-text MarmaladeまたはMELPAからパッケージをインストールして、次のコードを取得します。

これが私が使用するもので、リージョンと個々の回線の両方で機能します。

(defun move-text-internal (arg)
  (cond
   ((and mark-active transient-mark-mode)
    (if (> (point) (mark))
        (exchange-point-and-mark))
    (let ((column (current-column))
          (text (delete-and-extract-region (point) (mark))))
      (forward-line arg)
      (move-to-column column t)
      (set-mark (point))
      (insert text)
      (exchange-point-and-mark)
      (setq deactivate-mark nil)))
   (t
    (let ((column (current-column)))
      (beginning-of-line)
      (when (or (> arg 0) (not (bobp)))
        (forward-line)
        (when (or (< arg 0) (not (eobp)))
          (transpose-lines arg)
          (when (and (eval-when-compile
                       '(and (>= emacs-major-version 24)
                             (>= emacs-minor-version 3)))
                     (< arg 0))
            (forward-line -1)))
        (forward-line -1))
      (move-to-column column t)))))

(defun move-text-down (arg)
  "Move region (transient-mark-mode active) or current line
  arg lines down."
  (interactive "*p")
  (move-text-internal arg))

(defun move-text-up (arg)
  "Move region (transient-mark-mode active) or current line
  arg lines up."
  (interactive "*p")
  (move-text-internal (- arg)))


(global-set-key [M-S-up] 'move-text-up)
(global-set-key [M-S-down] 'move-text-down)

1
これをEmacsWikiに追加しました。ここにあります:emacswiki.org/emacs/MoveText
ocodo

ありがとう!コードはすでにそこにあったと思いますが(emacswiki.org/emacs/basic-edit-toolkit.el)、この新しいページは人々が見つけやすくなります。
sanityinc 2010年

ああ、かっこいい、これまで見たことがないのですが、basic-edit-toolkitがクリーンアップを使用できるようです。
ocodo 2010年

1
@mcbはい、ELPAパッケージはel-getを介してインストールできます。(最近、el-getの作成者でさえpackage.elに移行していることに注意してください。)完全な行を選択するには、現在の行をすばやく選択するか、現在の領域を拡張して完全な行を含める別の関数を作成することをお勧めします。次に、テキスト移動関数の前にその関数を呼び出します。
sanityinc 2014年

1
@sanityincありがとうございます。初めて使ったときはミニEmacs「O」を持っていました。良いもの!
JS。

31

あなたは試してみるべきdrag-stuffです!

単一の行、および選択した領域の行に対して、Eclipse Alt+ Up/Downとまったく同じように機能します。

それに加えて、Alt+ Left/で単語を移動することができますRight
これはまさにあなたが探しているものです!また、ELPAリポジトリからも入手できます。

他の解決策は私にはうまくいきませんでした。それらのいくつかはバグがあり(順序を変更しながら線を転置します、wtf?)、それらのいくつかは正確に選択された領域を移動し、線の選択されていない部分をそれらの位置に残しました。しかしdrag-stuff、Eclipseとまったく同じように機能します!

そしてさらに!地域を選択してAlt+ Left/ Right!を使用してみてください。これにより、選択した領域が1文字ずつ左または右に置き換えられます。すごい!

グローバルに有効にするには、次のコマンドを実行するだけです。

(drag-stuff-global-mode)

デフォルトのemacsキーマップをオーバーライドするため、実際には左右の動きをオプションにする必要があります。
ocodo 2014年

@Slomojo多分!emacswikiでそれを提案してみませんか?:)
ALEKS-ダニエルJakimenko-A。

1
以前はこれを使用していましたが、現在はスマートシフトを使用しています。水平移動用のDWIMが好きです。
jpkotta 2015

1
(drag-stuff-define-keys)キーバインドが機能し始める前に、initファイルに必要です。これはこのgithubで説明されています:github.com/rejeep/drag-stuff.el
agent18

11

行を上下に移動するためのインタラクティブな関数をいくつか作成しました。

;; move line up
(defun move-line-up ()
  (interactive)
  (transpose-lines 1)
  (previous-line 2))

(global-set-key [(control shift up)] 'move-line-up)

;; move line down
(defun move-line-down ()
  (interactive)
  (next-line 1)
  (transpose-lines 1)
  (previous-line 1))

(global-set-key [(control shift down)] 'move-line-down)

キーバインディングはIntelliJIDEAスタイルですが、好きなものを使用できます。おそらく、リージョンでも動作するいくつかの関数を実装する必要があります。


5

これは、現在の行またはアクティブな領域がまたがる行を移動するためのスニペットです。カーソル位置と強調表示された領域を尊重します。また、領域が線の境界で開始/終了しない場合でも、線が途切れることはありません。(日食に触発されています。「転置線」よりも日食の方が便利だと思いました。)

;; move the line(s) spanned by the active region up/down (line transposing)
;; {{{
(defun move-lines (n)
  (let ((beg) (end) (keep))
    (if mark-active 
        (save-excursion
          (setq keep t)
          (setq beg (region-beginning)
                end (region-end))
          (goto-char beg)
          (setq beg (line-beginning-position))
          (goto-char end)
          (setq end (line-beginning-position 2)))
      (setq beg (line-beginning-position)
            end (line-beginning-position 2)))
    (let ((offset (if (and (mark t) 
                           (and (>= (mark t) beg)
                                (< (mark t) end)))
                      (- (point) (mark t))))
          (rewind (- end (point))))
      (goto-char (if (< n 0) beg end))
      (forward-line n)
      (insert (delete-and-extract-region beg end))
      (backward-char rewind)
      (if offset (set-mark (- (point) offset))))
    (if keep
        (setq mark-active t
              deactivate-mark nil))))

(defun move-lines-up (n)
  "move the line(s) spanned by the active region up by N lines."
  (interactive "*p")
  (move-lines (- (or n 1))))

(defun move-lines-down (n)
  "move the line(s) spanned by the active region down by N lines."
  (interactive "*p")
  (move-lines (or n 1)))

1
私にとって、move-textパッケージは壊れていました。あなたのソリューションは私のシステムで完全に機能します。それをありがとう!
Rune Kaagaard 2016年


1

組み込みはありません。転置線(Cx Ct)は使用できますが、繰り返し使用することはできません。http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/の関数を見てください

それを地域に適応させるのも簡単なはずです。


1
ところで、リンクされたスニペットを使用することにした場合は、letステートメントを(let((col(current-column))(line-move-visual nil))に変更することをお勧めします。そうしないと、折り返し行でおかしな動作が発生します。
レオAlekseyev

1

transpose-paragraph機能はあなたを助けることができます。

Emacsマニュアルの転置セクションもご覧になることをお勧めします。基本的に:

C-t
Transpose two characters (transpose-chars).
M-t
Transpose two words (transpose-words).
C-M-t
Transpose two balanced expressions (transpose-sexps).
C-x C-t
Transpose two lines (transpose-lines).

0

これには、(Melpaの)スマートシフトパッケージを使用します。デフォルトでは、再バインドC-C <arrow>して行または領域を移動します。メジャーモード固有の量(c-basic-offsetやpython-indent-offsetなど)だけ水平方向に移動します。地域でも動作します。

;; binds C-C <arrows>
(when (require 'smart-shift nil 'noerror)
  (global-smart-shift-mode 1))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.