web-dev-qa-db-fra.com

Déplacer la ligne / région de haut en bas dans emacs

Quelle est la façon la plus simple de déplacer la région ou la ligne sélectionnée (s'il n'y a pas de sélection) vers le haut ou vers le bas dans emacs? Je recherche la même fonctionnalité que celle d'Eclipse (limitée à M-up, M-down).

78
fikovnik

Une ligne peut être déplacée en utilisant transpose-lines lié à C-x C-t. Je ne sais pas pour les régions.

J'ai trouvé this extrait elisp qui fait ce que vous voulez, sauf que vous devez changer les liaisons.

(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)
41
Martin Wickman

Mise à jour: Installez le move-text package de Marmalade ou MELPA pour obtenir le code suivant.

Voici ce que j'utilise, qui fonctionne à la fois sur les régions et sur les lignes individuelles:

(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)
48
sanityinc

Tu devrais essayer drag-stuff !

Cela fonctionne exactement comme Eclipse Alt+Up/Down pour les lignes simples, ainsi que pour les lignes de régions sélectionnées!

En plus de cela, il vous permet de déplacer des mots avec Alt+Left/Right
C'est exactement ce que vous cherchez! Et il est même disponible sur le ELPA repos !

D'autres solutions n'ont jamais fonctionné pour moi. Certains d'entre eux étaient bogués (transposant des lignes tout en changeant leur ordre, wtf?) Et certains se déplaçaient exactement dans la région sélectionnée, laissant des parties non sélectionnées des lignes sur leurs positions. Mais drag-stuff fonctionne exactement comme dans Eclipse!

Et encore plus! Vous pouvez essayer de sélectionner une région et d'utiliser Alt+Left/Right ! Cela transposera la région sélectionnée d'un caractère vers la gauche ou la droite. Incroyable!

Pour l'activer globalement, exécutez simplement ceci:

(drag-stuff-global-mode)

J'ai écrit quelques fonctions interactives pour déplacer des lignes vers le haut/bas:

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

Les raccourcis clavier sont IntelliJ IDEA style, mais vous pouvez utiliser tout ce que vous voulez. Je devrais probablement implémenter certaines fonctions qui fonctionnent également sur les régions.

8
Bozhidar Batsov

Il y a une entrée dans le wiki emacs juste pour ça:

http://www.emacswiki.org/emacs/MoveLine

Pour les régions en mouvement:

http://www.emacswiki.org/emacs/MoveRegion

4
Manuel

Voici mon extrait de code pour déplacer la ligne actuelle ou les lignes étendues par la région active. Il respecte la position du curseur et la région en surbrillance. Et il ne cassera pas les lignes lorsque la région ne commence pas/ne se termine pas aux bordures de ligne. (Il est inspiré par Eclipse; j'ai trouvé la méthode Eclipse plus pratique que les "lignes de transposition".)

;; 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)))
4
Ji Han

Il n'y a pas de fonction intégrée. Vous pouvez utiliser des lignes de transposition (C-x C-t) mais vous ne pouvez pas l'utiliser à plusieurs reprises. Regardez les fonctions sur http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/ .

Il devrait également être facile de l'adapter aux régions.

1
Florian Thiel

Le transpose-paragraph la fonction pourrait vous aider.

Vous pouvez également consulter la section transpose du manuel Emacs. Essentiellement:

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).
1
Roberto Aloi

J'utilise le package smart-shift (dans Melpa) pour cela. Par défaut, il lie à nouveau C-C <arrow> pour déplacer une ligne ou une région. Il se déplace horizontalement d'une quantité spécifique au mode principal (par exemple, décalage c-basique ou décalage en retrait python). Fonctionne également sur les régions.

;; binds C-C <arrows>
(when (require 'smart-shift nil 'noerror)
  (global-smart-shift-mode 1))
0
jpkotta