it-swarm.it

Come faccio a duplicare un'intera riga in Emacs?

Ho visto questa stessa domanda per VIM ed è stato qualcosa che io stesso volevo sapere come fare per Emacs. In ReSharper uso CTRL-D per questa azione. Qual è il numero minimo di comandi per eseguire questo in Emacs?

136
Ray Vega

Io uso 

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

che si rompe in

  • C-a: sposta il cursore all'inizio della riga
  • C-SPACE: inizia una selezione ("set mark")
  • C-n: sposta il cursore sulla riga successiva
  • M-w: copia regione
  • C-y: paste ("yank")

Il suddetto

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

equivale alla stessa cosa (TMTOWTDI)

  • C-a: sposta il cursore all'inizio della riga
  • C-k: taglia ("uccide") la linea
  • C-k: taglia la nuova riga
  • C-y: paste ("yank") (siamo di nuovo al punto di partenza)
  • C-y: incolla di nuovo (ora abbiamo due copie della linea)

Questi sono entrambi prolissi in modo imbarazzante rispetto a C-d nel tuo editor, ma in Emacs c'è sempre una personalizzazione. C-d è associato a delete-char per impostazione predefinita, quindi per quanto riguarda C-c C-d? Basta aggiungere quanto segue al tuo .emacs:

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

(Probabilmente è preferibile la versione elisp di Nathan, perché non si interromperà se qualcuno dei collegamenti dei tasti viene modificato).

Attenzione: alcune modalità Emacs possono recuperare C-c C-d per fare qualcos'altro.

135
Chris Conway

Oltre alle risposte precedenti puoi anche definire la tua funzione per duplicare una linea. Ad esempio, inserendo quanto segue nel file .emacs, C-d duplicherà la riga corrente.

(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

Posiziona il cursore sulla linea, se non all'inizio, fai una CTRL-A, poi:

CTRL-K

CTRL-K

CTRL-Y

CTRL-Y

60
epatel

La mia versione di una funzione per duplicare una linea che funziona con Annulla e non rovina la posizione del cursore. Era il risultato di una discussione in gnu.emacs.sources del 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))

Quindi puoi definire CTRL-D per chiamare questa funzione:

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

Invece di kill-line (C-k) come in C-aC-kC-kC-yC-y utilizza il comando kill-whole-line :

C-S-Backspace
C-y
C-y

I vantaggi rispetto a C-k includono che non importa dove sia il punto sulla linea (a differenza di C-k che richiede di essere all'inizio della riga) e uccide anche la nuova riga (di nuovo qualcosa che C-k non fa).

42
Ray Vega

Ecco un'altra funzione per farlo. La mia versione non tocca il kill ring e il cursore finisce sulla nuova riga in cui si trovava sull'originale. Duplicherà la regione se è attiva (modalità di segno transitorio), o predefinita per duplicare la linea in caso contrario. Produrrà anche più copie se viene fornito un prefisso arg e commenta la riga originale se viene fornito un prefisso negativo arg (questo è utile per testare una versione diversa di un comando/istruzione mantenendo quello vecchio).

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

Ho legato a C-c d:

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

Questo non dovrebbe mai essere riassegnato da una modalità o altro perché C-c seguito da una singola lettera (non modificata) è riservata ai binding dell'utente.

24
qmega

L'aggiunta di Nathan al tuo file .emacs è la strada da percorrere ma potrebbe essere leggermente semplificata sostituendo 

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

con

  (newline)

cedevole

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

installa duplicate-thing da melpa:

M-x install-install RET duplicate-thing

e aggiungi questa combinazione di tasti a init file :

(global-set-key (kbd "M-c") 'duplicate-thing)

5
user2626414

Non ricordo bene come la duplicazione della linea funzioni da qualche altra parte, ma come ex utente di SciTE mi è piaciuta una cosa su SciTE-way: non tocca la posizione del cursore! Quindi tutte le ricette sopra non erano abbastanza buone per me, ecco la mia versione 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))))

Si noti che nulla viene effettivamente ucciso durante il processo, lasciando intatti i segni e la selezione corrente.

A proposito, perché voi ragazzi siete così affezionati a muovere il cursore quando c'è questo simpaticone dell'holly-whole-thingy (C-S-backspace)?

5
mk-fg

Ho copy-from-above-command associato a una chiave e lo uso. È fornito con XEmacs, ma non so su GNU Emacs.

`copy-from-above-command 'è un funzione LISP compilata interattiva
- caricato da "/usr/share/xemacs/21.4.15/LISP/misc.elc" (copia-da-sopra-comando & facoltativo ARG)

Documentazione: Copia caratteri da precedente linea non vuota , che inizia con sopra il punto. Copia i caratteri ARG, ma non oltre la fine di quella linea. Se no argomento fornito, copia l'intero resto della linea. I caratteri copiati sono inserito nel buffer prima del punto.

4
Darron

perché non lo so, inizierò questo round di golf con un rallentatore:

ctrl-k, y, y

4
Kevin Conner

Con emac recenti, puoi usare M-w in qualsiasi punto della linea per copiarlo. Quindi diventa:

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

è qualcosa che potresti voler avere nel tuo .emacs 

(setq kill-whole-line t)

Che praticamente uccide l'intera linea più la nuova linea ogni volta che invochi kill-line (cioè via C-k). Quindi, senza codice aggiuntivo, puoi semplicemente fare C-a C-k C-y C-y per duplicare la linea. Si rompe a 

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.

Ma se lo usi spesso, forse un legame chiave dedicato potrebbe essere un'idea migliore, ma il vantaggio di usare solo C-a C-k C-y C-y è che puoi duplicare la riga altrove, invece che appena sotto la linea corrente.

3
polyglot

Le impostazioni predefinite sono orribili per questo. Tuttavia, puoi estendere Emacs affinché funzioni come SlickEdit e TextMate, ovvero copia/taglia la linea corrente quando non è selezionato alcun testo:

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

Posiziona quanto sopra in .emacs. Quindi, per copiare una riga, M-w. Per eliminare una riga, C-w. Per duplicare una riga, C-a M-w C-y C-y C-y ....

3
Marius Andersen

Ho visto soluzioni molto complesse, comunque ...

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

'Ho scritto la mia versione di duplicate-line, perché non voglio rovinare l'anello della morte.

  (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

C'è un pacchetto chiamato Avy Ha il comando avy-copy-line. Quando usi questo comando, ogni riga nella tua finestra ottiene una combinazione di lettere. Quindi devi solo digitare la combinazione e ottenere quella linea. Questo funziona anche per la regione. Quindi devi solo digitare due combinazioni.

Qui puoi vedere l'interfaccia: 

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

3
teksturi

@ [Kevin Conner]: Abbastanza vicino, per quanto ne so. L'unica altra cosa da considerare è attivare kill-whole-line per includere la nuova riga nel C-k.

2
Allen

Mi è piaciuta la versione di FraGGod, ad eccezione di due cose: (1) Non controlla se il buffer è già di sola lettura con (interactive "*"), e (2) fallisce sull'ultima riga del buffer se quest'ultima riga è vuota (come non puoi uccidere la linea in quel caso), lasciando il tuo buffer di sola lettura.

Ho apportato le seguenti modifiche per risolvere il problema:

(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

Se chiamato in modo interattivo senza regione attiva, COPY (M-w) una singola riga invece:

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

Quando viene chiamato in modo interattivo senza alcuna regione attiva, KILL (C-w) invece una singola riga.

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

Inoltre, su una nota correlata:

(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

Ne scrivo uno per la mia preferenza.

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

Ma ho trovato che avrebbe qualche problema quando la riga corrente contiene caratteri multibyte (ad esempio caratteri CJK). Se incontri questo problema, prova questo:

(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, (posizione in una nuova posizione) ctrl-y

Aggiungere un ctrl-a se non stai iniziando all'inizio della linea. E il 2 ° ctrl-k è quello di afferrare il carattere di nuova riga. Può essere rimosso se vuoi solo il testo.

1
CJP

Questa funzionalità deve corrispondere all'implementazione di JetBrains in termini di duplicazione per riga o regione e quindi lasciando il punto e/o l'area attiva come previsto:

Solo un wrapper per il modulo interattivo:

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

Questo lo chiama,

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

O questo

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

E poi ho legato a meta + shift + d

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

M-c, Shift+Insertx2 (o qualsiasi altra cosa è la tua scorciatoia di incollare) lo farà.

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.

aggiungi l'elis qui sopra a te init.el, e ora hai la funzione taglia/copia linea intera, quindi puoi F3 F4 per duplicare una linea.

0
WisdomFusion

Questo sembra più naturale, rispetto alla risposta selezionata di Chris Conway.

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

Ciò consente di duplicare una riga più volte semplicemente ripetendo i tratti di tasto\C-c\C-d.

0
Shim Kporku

Ecco una funzione per duplicare la linea corrente. Con gli argomenti prefisso, duplica la riga più volte. Ad esempio, C-3 C-S-o duplicherà la riga corrente tre volte. Non cambia kill ring. 

(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

Come accennato in altre risposte, i tratti chiave vincolanti per il codice LISP sono un'idea migliore rispetto a vincolarli a un altro tratto chiave. Con la risposta di @ mw, il codice duplica la linea e sposta il segno alla fine della nuova riga. Questa modifica mantiene la posizione del segno sulla stessa colonna della nuova riga:

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

Non posso credere a tutte queste complicate soluzioni. Questo è due tasti:

<C-S-backspace> esegue il comando kill-whole-line

C-/ esegue il comando annulla

Quindi <C-S-backspace> C-/ per "copiare" un'intera riga (uccidere e annullare).

Ovviamente puoi combinarlo con gli argomenti numerici e negativi per eliminare più righe in avanti o all'indietro.

0
Andy

Il modo più semplice è il metodo di Chris Conway. 

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

Questo è il modo predefinito richiesto da EMACS. Secondo me, è meglio usare lo standard. Sono sempre attento alla personalizzazione del proprio legame con le chiavi in ​​EMACS. EMACS è già abbastanza potente, penso che dovremmo fare del nostro meglio per adattarci ai suoi legami chiave. 

Anche se è un po 'lungo, ma quando ci si abitua, si può fare velocemente e scoprirlo è divertente!

0
linbianxiaocao

Con gli argomenti prefisso e cosa è (spero) il comportamento intuitivo:

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

Il cursore rimarrà sull'ultima riga . In alternativa, potresti voler specificare un prefisso per duplicare contemporaneamente le righe seguenti:

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

Mi trovo ad usare entrambi spesso, usando una funzione wrapper per cambiare il comportamento dell'argomento prefisso.

E una combinazione di tasti: (global-set-key (kbd "C-S-d") 'duplicate-line)

0
Karthik