web-dev-qa-db-fra.com

Comment dupliquer une ligne entière dans Emacs?

J'ai vu cette même question pour VIM et c'est quelque chose que je voulais moi-même savoir faire pour Emacs. Dans ReSharper, j'utilise CTRL-D pour cette action. Quel est le plus petit nombre de commandes à effectuer dans Emacs?

136
Ray Vega

J'utilise 

C-a C-SPACE C-n M-w C-y

qui se décompose en

  • C-a: déplace le curseur au début de la ligne
  • C-SPACE: commencer une sélection ("marque définie")
  • C-n: déplace le curseur à la ligne suivante
  • M-w: région de copie
  • C-y: coller ("tirer")

Le susdit

C-a C-k C-k C-y C-y

équivaut à la même chose (TMTOWTDI)

  • C-a: déplace le curseur au début de la ligne
  • C-k: coupe ("tue") la ligne
  • C-k: coupe la nouvelle ligne
  • C-y: coller ("yank") (nous sommes de retour à la case départ)
  • C-y: coller à nouveau (maintenant nous avons deux copies de la ligne)

Celles-ci sont à la fois gênantes et embarrassantes par rapport à C-d dans votre éditeur, mais il existe toujours une personnalisation dans Emacs. C-d est lié à delete-char par défaut, alors pourquoi pas C-c C-d? Ajoutez simplement ce qui suit à votre .emacs:

(global-set-key "\C-c\C-d" "\C-a\C- \C-n\M-w\C-y")

(La version elisp de @ Nathan est probablement préférable, car elle ne casse pas si l'une des liaisons de clé est modifiée.)

Attention: certains modes Emacs peuvent récupérer C-c C-d pour faire autre chose.

135
Chris Conway

En plus des réponses précédentes, vous pouvez également définir votre propre fonction pour dupliquer une ligne. Par exemple, si vous ajoutez ce qui suit dans votre fichier .emacs, C-d dupliquera la ligne actuelle.

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (open-line 1)
  (next-line 1)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)
92
Nate

Placez le curseur sur la ligne, sinon au début faites un CTRL-A, puis:

CTRL-K

CTRL-K

CTRL-Y

CTRL-Y

60
epatel

Ma version d'une fonction pour dupliquer une ligne qui fonctionne bien avec undo et ne joue pas avec la position du curseur. C'était le résultat d'un discussion dans gnu.emacs.sources de novembre 1997 .

(defun duplicate-line (arg)
  "Duplicate current line, leaving point in lower line."
  (interactive "*p")

  ;; save the point for undo
  (setq buffer-undo-list (cons (point) buffer-undo-list))

  ;; local variables for start and end of line
  (let ((bol (save-excursion (beginning-of-line) (point)))
        eol)
    (save-excursion

      ;; don't use forward-line for this, because you would have
      ;; to check whether you are at the end of the buffer
      (end-of-line)
      (setq eol (point))

      ;; store the line and disable the recording of undo information
      (let ((line (buffer-substring bol eol))
            (buffer-undo-list t)
            (count arg))
        ;; insert the line arg times
        (while (> count 0)
          (newline)         ;; because there is no newline in 'line'
          (insert line)
          (setq count (1- count)))
        )

      ;; create the undo information
      (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))
    ) ; end-of-let

  ;; put the point in the lowest line and return
  (next-line arg))

Ensuite, vous pouvez définir CTRL-D pour appeler cette fonction:

(global-set-key (kbd "C-d") 'duplicate-line)
51
pesche

Au lieu de kill-line (C-k) comme dans C-aC-kC-kC-yC-y, utilisez la commande kill-whole-line :

C-S-Backspace
C-y
C-y

Les avantages par rapport à C-k sont notamment le fait que l'emplacement du point importe peu (contrairement à C-k qui nécessite d'être au début de la ligne) et qu'il supprime également la nouvelle ligne (là encore, quelque chose que C-k ne fait pas).

42
Ray Vega

Voici encore une autre fonction pour faire cela. Ma version ne touche pas l'anneau de mise à mort et le curseur se termine sur la nouvelle ligne où il se trouvait sur l'original. Elle dupliquera la région si elle est active (mode de repère transitoire) ou, par défaut, dupliquera la ligne. Il fera également plusieurs copies si un préfixe arg est donné et commente la ligne d'origine si un préfixe négatif lui est attribué (utile pour tester une version différente d'une commande/instruction tout en conservant l'ancienne).

(defun duplicate-line-or-region (&optional n)
  "Duplicate current line, or region if active.
With argument N, make N copies.
With negative N, comment out original line and use the absolute value."
  (interactive "*p")
  (let ((use-region (use-region-p)))
    (save-excursion
      (let ((text (if use-region        ;Get region if active, otherwise line
                      (buffer-substring (region-beginning) (region-end))
                    (prog1 (thing-at-point 'line)
                      (end-of-line)
                      (if (< 0 (forward-line 1)) ;Go to beginning of next line, or make a new one
                          (newline))))))
        (dotimes (i (abs (or n 1)))     ;Insert N times, or once if not specified
          (insert text))))
    (if use-region nil                  ;Only if we're working with a line (not a region)
      (let ((pos (- (point) (line-beginning-position)))) ;Save column
        (if (> 0 n)                             ;Comment out original with negative arg
            (comment-region (line-beginning-position) (line-end-position)))
        (forward-line 1)
        (forward-char pos)))))

Je l'ai lié à C-c d:

(global-set-key [?\C-c ?d] 'duplicate-line-or-region)

Cela ne devrait jamais être réaffecté par un mode ou quoi que ce soit, car C-c suivi d'une seule lettre (non modifiée) est réservé aux liaisons utilisateur.

24
qmega

L’ajout de Nathan à votre fichier .emacs est la voie à suivre, mais il pourrait être légèrement simplifié en remplaçant 

  (open-line 1)
  (next-line 1)

avec

  (newline)

cédant

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (newline)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)
16
pw.

installez duplicate-thing depuis melpa:

M-x package-install RET duplicate-thing

et ajoutez ce raccourci clavier à fichier init :

(global-set-key (kbd "M-c") 'chose dupliquée)

5
user2626414

Je ne me souviens pas très bien comment la duplication de lignes fonctionne ailleurs, mais en tant qu'ancien utilisateur de SciTE, j'aimais une chose à propos de SciTE-way: elle ne touche pas la position du curseur! Donc, toutes les recettes ci-dessus ne sont pas suffisantes. pour moi, voici ma version hippie:

(defun duplicate-line ()
    "Clone line at cursor, leaving the latter intact."
    (interactive)
    (save-excursion
        (let ((kill-read-only-ok t) deactivate-mark)
            (toggle-read-only 1)
            (kill-whole-line)
            (toggle-read-only 0)
            (yank))))

Notez que rien n'est réellement tué dans le processus, en laissant intactes les marques et la sélection actuelle.

BTW, pourquoi vous êtes tellement friands de secousses du curseur quand il y a ce truc Nice'n'clean kill-line-line (C-S-backspace)?

5
mk-fg

J'ai copy-from-above-command lié à une clé et l'utiliser. Il est fourni avec XEmacs, mais je ne connais pas Emacs GNU.

`copy-from-above-command 'est un fonction LISP compilée interactive
- chargé depuis "/usr/share/xemacs/21.4.15/LISP/misc.elc" (copy-from-above-command & facultatif ARG)

Documentation: Copier les caractères de ligne non vide précédente , commençant juste au-dessus du point. Copiez les caractères ARG, mais pas au-delà de la fin de cette ligne. Sinon argument donné, copier le reste en entier de la ligne. Les caractères copiés sont inséré dans le tampon avant le point.

4
Darron

parce que je ne sais pas, je vais commencer cette partie de golf avec un slowball:

ctrl-k, y, y

4
Kevin Conner

Avec les récents emacs, vous pouvez utiliser M-w n'importe où dans la ligne pour le copier. Alors ça devient:

M-w C-a RET C-y
3
Louis Kottmann
C-a C-k C-k C-y C-y
3
sverrejoh

quelque chose que vous voudrez peut-être avoir dans votre .emacs est 

(setq kill-whole-line t)

Ce qui tue la ligne entière plus la nouvelle ligne chaque fois que vous appelez kill-line (c.-à-d. Via C-k). Ensuite, sans code supplémentaire, vous pouvez simplement faire C-a C-k C-y C-y pour dupliquer la ligne. Il se décompose en 

C-a go to beginning of line
C-k kill-line (i.e. cut the line into clipboard)
C-y yank (i.e. paste); the first time you get the killed line back; 
    second time gives the duplicated line.

Mais si vous utilisez cela souvent, une liaison de clé dédiée pourrait peut-être être une meilleure idée, mais l'avantage de simplement utiliser C-a C-k C-y C-y est que vous pouvez dupliquer la ligne ailleurs, plutôt que juste en dessous de la ligne actuelle.

3
polyglot

Les valeurs par défaut sont horribles pour cela. Cependant, vous pouvez étendre Emacs pour qu’il fonctionne comme SlickEdit et TextMate, c’est-à-dire copier/couper la ligne actuelle quand aucun texte n’est sélectionné:

(transient-mark-mode t)
(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, copy a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))
(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
           (line-beginning-position 2)))))

Placez ce qui précède dans .emacs. Ensuite, pour copier une ligne, M-w. Pour supprimer une ligne, C-w. Pour dupliquer une ligne, C-a M-w C-y C-y C-y ....

3
Marius Andersen

J'ai vu des solutions très complexes, de toute façon ...

(defun duplicate-line ()
  "Duplicate current line"
  (interactive)
  (kill-whole-line)
  (yank)
  (yank))
(global-set-key (kbd "C-x M-d") 'duplicate-line)
3
user6581334

'J'ai écrit ma propre version de duplicate-line, parce que je ne veux pas tout bousiller.

  (defun jr-duplicate-line ()
    "EASY"
    (interactive)
    (save-excursion
      (let ((line-text (buffer-substring-no-properties
                        (line-beginning-position)
                        (line-end-position))))
        (move-end-of-line 1)
        (newline)
        (insert line-text))))
  (global-set-key "\C-cd" 'jr-duplicate-line)
3
Joyer

Il y a un paquet appelé Avy Il a la commande avy-copy-line. Lorsque vous utilisez cette commande, chaque ligne de votre fenêtre reçoit une combinaison de lettres. Ensuite, il vous suffit de taper la combinaison et vous obtenez cette ligne. Cela fonctionne également pour la région. Ensuite, il vous suffit de taper deux combinaisons.

Ici vous pouvez voir l'interface: 

http://i68.tinypic.com/24fk5eu.png

3
teksturi

@ [Kevin Conner]: Assez proche, pour autant que je sache. La seule autre chose à considérer est d'activer kill-whole-line pour inclure la nouvelle ligne dans le C-k.

2
Allen

J'ai aimé la version de FraGGod, à l'exception de deux choses: (1) il ne vérifie pas si le tampon est déjà en lecture seule avec (interactive "*"), et (2) il échoue sur la dernière ligne du tampon si cette dernière ligne est vide (comme vous ne pouvez pas tuer la ligne dans ce cas), en laissant votre tampon en lecture seule.

J'ai apporté les modifications suivantes pour résoudre ce problème:

(defun duplicate-line ()
  "Clone line at cursor, leaving the latter intact."
  (interactive "*")
  (save-excursion
    ;; The last line of the buffer cannot be killed
    ;; if it is empty. Instead, simply add a new line.
    (if (and (eobp) (bolp))
        (newline)
      ;; Otherwise kill the whole line, and yank it back.
      (let ((kill-read-only-ok t)
            deactivate-mark)
        (toggle-read-only 1)
        (kill-whole-line)
        (toggle-read-only 0)
        (yank)))))
2
phils

Lorsque vous appelez de manière interactive sans région active, COPY (M-w) à la place:

(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, COPY a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

Lorsque vous appelez de manière interactive sans région active, KILL (C-w) à la place.

(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, KILL a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Killed line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

En outre, sur une note connexe:

(defun move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode))

(defun move-line-down ()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode))

(global-set-key [(meta shift up)]  'move-line-up)
(global-set-key [(meta shift down)]  'move-line-down)
2
yPhil

J'en écris un à ma préférence.

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
        (cur-col (current-column)))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)

Mais j'ai constaté que cela poserait un problème lorsque la ligne en cours contient des caractères multi-octets (par exemple, des caractères CJK). Si vous rencontrez ce problème, essayez plutôt ceci:

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let* ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
         (cur-col (length (buffer-substring-no-properties (point-at-bol) (point)))))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)
1
kuanyui

ctrl-kctrl-k, (position au nouvel emplacement) ctrl-y

Ajouter un ctrl-a si vous ne commencez pas au début de la ligne. Et le 2 ctrl-k est de saisir le caractère de nouvelle ligne. Il peut être supprimé si vous voulez juste le texte.

1
CJP

Cette fonctionnalité doit correspondre à l'implémentation de JetBrains en termes de duplication à la fois par ligne ou par région, puis en laissant le point et/ou la région active comme prévu:

Juste un wrapper autour du formulaire interactif:

(defun wrx/duplicate-line-or-region (beg end)
  "Implements functionality of JetBrains' `Command-d' shortcut for `duplicate-line'.
   BEG & END correspond point & mark, smaller first
   `use-region-p' explained: 
   http://emacs.stackexchange.com/questions/12334/elisp-for-applying-command-to-only-the-selected-region#answer-12335"
  (interactive "r")
  (if (use-region-p)
      (wrx/duplicate-region-in-buffer beg end)
    (wrx/duplicate-line-in-buffer)))

Qui appelle ça,

(defun wrx/duplicate-region-in-buffer (beg end)
  "copy and duplicate context of current active region
   |------------------------+----------------------------|
   |        before          |           after            |
   |------------------------+----------------------------|
   | first <MARK>line here  | first line here            |
   | second item<POINT> now | second item<MARK>line here |
   |                        | second item<POINT> now     |
   |------------------------+----------------------------|
   TODO: Acts funky when point < mark"
  (set-mark-command nil)
  (insert (buffer-substring beg end))
  (setq deactivate-mark nil))

Ou ca

(defun wrx/duplicate-line-in-buffer ()
  "Duplicate current line, maintaining column position.
   |--------------------------+--------------------------|
   |          before          |          after           |
   |--------------------------+--------------------------|
   | lorem ipsum<POINT> dolor | lorem ipsum dolor        |
   |                          | lorem ipsum<POINT> dolor |
   |--------------------------+--------------------------|
   TODO: Save history for `Cmd-Z'
   Context: 
   http://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs#answer-551053"
  (setq columns-over (current-column))
  (save-excursion
    (kill-whole-line)
    (yank)
    (yank))
  (let (v)
    (dotimes (n columns-over v)
      (right-char)
      (setq v (cons n v))))
  (next-line))

Et puis j'ai ceci lié à meta + shift + d

(global-set-key (kbd "M-D") 'wrx/duplicate-line-or-region)
1
AesopHimself

M-c, Shift+Insertx2 (ou quel que soit votre raccourci de collage) le fera.

0
Andrew Naguib
;; http://www.emacswiki.org/emacs/WholeLineOrRegion#toc2
;; cut, copy, yank
(defadvice kill-ring-save (around slick-copy activate)
  "When called interactively with no active region, copy a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (buffer-substring (line-beginning-position)
                                (line-beginning-position 2))
              nil '(yank-line))
    (message "Copied line")))
(defadvice kill-region (around slick-copy activate)
  "When called interactively with no active region, kill a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (filter-buffer-substring (line-beginning-position)
                                       (line-beginning-position 2) t)
              nil '(yank-line))))
(defun yank-line (string)
  "Insert STRING above the current line."
  (beginning-of-line)
  (unless (= (elt string (1- (length string))) ?\n)
    (save-excursion (insert "\n")))
  (insert string))

(global-set-key (kbd "<f2>") 'kill-region)    ; cut.
(global-set-key (kbd "<f3>") 'kill-ring-save) ; copy.
(global-set-key (kbd "<f4>") 'yank)           ; paste.

ajoutez le elisp ci-dessus à init.el, et vous obtenez la fonction de coupe/copie de la ligne complète maintenant, alors vous pouvez F3 F4 pour dupliquer une ligne.

0
WisdomFusion

Cela semble plus naturel en ce qui concerne la réponse choisie par Chris Conway.

(clé globale "\ C-C\C-d" "\ C-a\C-\ C-n\M-w\C-y\C-p\C-e")

Cela vous permet de dupliquer une ligne plusieurs fois en répétant simplement les touches\C-c\C-d.

0
Shim Kporku

Voici une fonction pour dupliquer la ligne en cours. Avec les arguments préfixés, la ligne sera dupliquée plusieurs fois. Par exemple, C-3 C-S-o dupliquera la ligne en cours trois fois. Ne change pas le killer. 

(defun duplicate-lines (arg)
  (interactive "P")
  (let* ((arg (if arg arg 1))
         (beg (save-excursion (beginning-of-line) (point)))
         (end (save-excursion (end-of-line) (point)))
         (line (buffer-substring-no-properties beg end)))
    (save-excursion
      (end-of-line)
      (open-line arg)
      (setq num 0)
      (while (< num arg)
        (setq num (1+ num))
        (forward-line 1)
        (insert-string line))
      )))

(global-set-key (kbd "C-S-o") 'duplicate-lines)
0
Dodgie

Comme mentionné dans d'autres réponses, lier les touches au code LISP est une meilleure idée que de les lier à d'autres touches. Avec la réponse de @ mw, le code duplique la ligne et déplace la marque à la fin de la nouvelle ligne. Cette modification maintient la position de la marque sur la même colonne sur la nouvelle ligne:

fun duplicate-line ()
  (interactive)
  (let ((col (current-column)))
    (move-beginning-of-line 1)
    (kill-line)
    (yank)
    (newline)
    (yank)
    (move-to-column col)))
0
krsoni

Je ne peux pas croire toutes ces solutions compliquées. Ce sont deux frappes:

<C-S-backspace> exécute la commande kill-whole-line

C-/ exécute la commande undo

Donc <C-S-backspace> C-/ pour "copier" une ligne entière (kill et undo).

Vous pouvez bien sûr combiner cela avec des arguments numériques et négatifs pour supprimer plusieurs lignes, en avant ou en arrière.

0
Andy

Le moyen le plus simple est la méthode de Chris Conway. 

C-a C-SPACE C-n M-w C-y

C'est la méthode par défaut prescrite par EMACS. À mon avis, il est préférable d'utiliser la norme. Je suis toujours attentif à la personnalisation de la liaison de clé dans EMACS. EMACS est déjà assez puissant, je pense que nous devrions faire de notre mieux pour nous adapter à ses propres raccourcis clavier. 

Bien que ce soit un peu long, mais quand vous y êtes habitué, vous pouvez faire vite et trouver que c'est amusant!

0
linbianxiaocao

Avec les arguments préfixés, et quel est (j'espère) un comportement intuitif:

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (next-line 
   (save-excursion 
     (let ((beg (line-beginning-position))
           (end (line-end-position)))
       (copy-region-as-kill beg end)
       (dotimes (num arg arg)
         (end-of-line) (newline)
         (yank))))))

Le curseur restera sur la dernière ligne . Sinon, vous pouvez spécifier un préfixe pour dupliquer les quelques lignes suivantes à la fois:

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (save-excursion 
    (let ((beg (line-beginning-position))
          (end 
           (progn (forward-line (1- arg)) (line-end-position))))
      (copy-region-as-kill beg end)
      (end-of-line) (newline)
      (yank)))
  (next-line arg))

Je me trouve souvent en train d'utiliser les deux fonctions, en utilisant une fonction wrapper pour changer le comportement de l'argument préfixe.

Et un raccourci clavier: (global-set-key (kbd "C-S-d") 'duplicate-line)

0
Karthik