Como duplico uma linha inteira no Emacs?


Respostas:


150

eu uso

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

que se divide em

  • C-a: move o cursor para o início da linha
  • C-SPACE: inicia uma seleção ("set mark")
  • C-n: move o cursor para a próxima linha
  • M-w: copiar região
  • C-y: colar ("puxar")

O mencionado acima

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

equivale à mesma coisa (TMTOWTDI)

  • C-a: move o cursor para o início da linha
  • C-k: cortar ("matar") a linha
  • C-k: cortar a nova linha
  • C-y: paste ("yank") (estamos de volta à estaca zero)
  • C-y: cole novamente (agora temos duas cópias da linha)

Ambos são embaraçosamente detalhados em comparação com o C-dseu editor, mas no Emacs sempre há uma personalização. C-destá vinculado delete-charpor padrão, e daí C-c C-d? Basta adicionar o seguinte ao seu .emacs:

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

(A versão elisp de Nathan é provavelmente preferível, porque não será interrompida se alguma das combinações de teclas for alterada.)

Cuidado: alguns modos do Emacs podem se recuperar C-c C-dpara fazer outra coisa.


5
Oi! Esteja ciente de que se você tiver '(setq kill-whole-line t)', precisará apenas de um 'Ck' (solução 2), pois ele já mata a nova linha junto com o conteúdo da linha. Meu uso preferido de 'C-k'. Cheers, Daniel
danielpoe 16/02/09

179
Isso é realmente constrangedor.
Tofutim

18
Que tal C-S-backspace C-y C-y?
ericzma

1
o que é Mw? qual chave usar para isso?
Bala

4
@Bala "M" é "Meta" (geralmente Esc ou Alt, depende do layout do teclado). "Mw" é "Meta" e "w" simultaneamente (no teclado, "Alt-w").
Chris Conway

96

Além das respostas anteriores, você também pode definir sua própria função para duplicar uma linha. Por exemplo, colocar o seguinte no seu arquivo .emacs fará com que o Cd duplique a linha atual.

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

Estou recebendo o seguinte erro com este:Symbol's function definition is void: move-beginning-of-line
Rohaq 13/03

5
O problema com isto é que a tecla "Del" também é binded a duplicação da linha ...
David Gomes

Então, alguma idéia de como desvincular Deldessa função?
Alexander Shcheblikin

OK, encontrou uma solução para Delvoltar ao normal, mantendo o novo C-d: (global-set-key (kbd "<delete>") 'delete-char)precisa ser adicionado após a C-ddefinição.
Alexander Shcheblikin

Tentar isso em uma linha vazia resulta na inserção de duas linhas, em vez de apenas uma. Não sei porque. Existe uma solução fácil?
Zelphir Kaltstahl

68

Coloque o cursor na linha, se não estiver no início, faça um CTRL- A, então:

CTRL-K

CTRL-K

CTRL-Y

CTRL-Y


Eu não acho que o segundo CY seja necessário.
Bastien Léonard

4
não será uma duplicata sem
epatel

17
Use CS-Backspace (kill-whole-line) em vez de Ck. Você não precisa estragar a posição do cursor ou eliminar a nova linha.
Nietzche-jou

Isso funciona bem, mas não existe uma maneira curta de fazer isso?
Stryker

52

Minha versão de uma função para duplicar uma linha que funciona bem com desfazer e não mexe com a posição do cursor. Foi o resultado de uma discussão no gnu.emacs.sources de novembro de 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))

Então você pode definir CTRL-D para chamar esta função:

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

Excelente! O recurso desfazer e posição do cursor torna este o melhor. Obrigado!
PTRN

Além disso, no link, também há algum código para regiões!
pcarvalho 02/03

Solução muito boa. Thx
Plankalkül

Funciona bem. Obrigado pela solução.
Stryker

O @pesche crux-duplicate-current-line-or-regionfunciona melhor para mim, porque com sua função ele desfaz a duplicação de linha e a última operação também.
Rofrol 01/08/19

47

Em vez de kill-line( C-k) como em C-a C-k C-k C-y C-y uso, o kill-whole-linecomando:

C-S-Backspace
C-y
C-y

As vantagens C-kincluem que não importa onde o ponto está na linha (ao contrário do C-kque exige estar no início da linha) e também mata a nova linha (novamente algo C-knão serve).


2
Kudos @RayVega! Eu tentei esta solução e ela funciona como um campeão (no meu GNU Emacs 23.3.1, enfim). Esta solução não está funcionando para algumas pessoas? Esta é a melhor resposta para sua (própria) pergunta.
JS.

1
Você deve aceitar esta resposta como a correta. Ele faz exatamente o que você pediu e no "menor número de comandos".
Davor Cubranic

24

Aqui está outra função para fazer isso. Minha versão não toca no anel final e o cursor termina na nova linha em que estava no original. Ele duplicará a região se estiver ativo (modo de marca transitória) ou o padrão será duplicar a linha. Ele também fará várias cópias se receber um prefixo arg e comentar a linha original se receber um prefixo negativo arg (isso é útil para testar uma versão diferente de um comando / instrução, mantendo a antiga).

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

Eu tenho que vincular a C-c d:

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

Isso nunca deve ser reatribuído por um modo ou qualquer coisa, porque C-cseguido por uma única letra (não modificada) é reservada para ligações do usuário.


Melhor solução até agora
Leo Ufimtsev

1
Coloquei isso no meu arquivo .emacs, mas quando tento usar C-c d, recebo o erro command-execute: Wrong type argument: commandp, duplicate-line-or-region. Alguma idéia do que se passa? Estou usando o Emacs 25.1.1 no Windows
junius

Solução muito boa, eu aprecio o recurso de região e o recurso de comentar com argumento negativo. Também como a ligação de chave sugerida.
Alex Trueman

18

A adição de Nathan ao seu arquivo .emacs é o caminho a seguir, mas poderia ser um pouco simplificada substituindo

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

com

  (newline)

produzindo

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

Isso é legal. Obrigado!
Tejasbubane # 4/17

7

instale coisa duplicada do melpa:

Mx pacote-instalar RET duplicado-coisa

e adicione esta combinação de teclas ao arquivo init :

(coisa duplicada da chave de conjunto global (kbd "Mc")))


Parece que não está lá nessas datas.
MarkSkayff

5

Não me lembro bem como a duplicação de linhas funciona em qualquer outro lugar, mas como um ex-usuário do SciTE, gostei de algo no SciTE-way: ele não toca na posição do cursor! Portanto, todas as receitas acima não eram boas o suficiente para mim, aqui está a minha versão 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))))

Observe que nada é realmente eliminado no processo, deixando marcas e a seleção atual intacta.

BTW, por que vocês gostam tanto de puxar o cursor quando existe esse negócio legal de matar toda a linha (CS-backspace)?


4

porque eu não sei, vou começar essa partida com uma bola lenta:

ctrl-k, y, y


4

algo que você pode querer ter no seu .emacs é

(setq kill-whole-line t)

O que basicamente mata a linha inteira mais a nova linha sempre que você chama a linha de interrupção (ou seja, via Ck). Então, sem código extra, você pode simplesmente fazer Ca Ck Cy Cy para duplicar a linha. Quebra para

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.

Mas se você usar isso com frequência, talvez uma ligação de tecla dedicada possa ser uma idéia melhor, mas a vantagem de usar apenas o Ca Ck Cy Cy é que você pode duplicar a linha em outro lugar, em vez de logo abaixo da linha atual.


4

Eu copy-from-above-commandvinculei a uma chave e use isso. É fornecido com o XEmacs, mas eu não sei sobre o GNU Emacs.

`copy-from-above-command 'é uma função interativa do Lisp compilada
- carregada em" /usr/share/xemacs/21.4.15/lisp/misc.elc "(cópia do comando acima e ARG opcional)

Documentação: Copie caracteres da linha anterior não vazia , começando logo acima do ponto. Copie caracteres ARG, mas não depois do final dessa linha. Se nenhum argumento for fornecido, copie o restante da linha. Os caracteres copiados são inseridos no buffer antes do ponto.


Quanto à versão 23, também faz parte da distribuição padrão do GNU Emacs.
viam0Zah

Não parece estar na minha versão. Algo precisa ser carregado? Minha versão é GNU Emacs 23.2.1 (amd64-portbld-freebsd8.1) of 2010-11-14 on [host clipped].
Qmega

2
@qmega Você precisa fazer (requer vários).
Dmitry

4

Existe um pacote chamado Avy. Ele possui o comando avy-copy-line. Quando você usa esse comando, todas as linhas da sua janela obtêm uma combinação de letras. Então você só precisa digitar a combinação e obter essa linha. Isso também funciona para a região. Então você só precisa digitar duas combinações.

Aqui você pode ver a interface:

insira a descrição da imagem aqui



3

Os padrões são horríveis para isso. No entanto, você pode estender o Emacs para funcionar como SlickEdit e TextMate, ou seja, copiar / cortar a linha atual quando nenhum texto for selecionado:

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

Coloque o item acima em .emacs. Então, para copiar uma linha M-w,. Para excluir uma linha C-w,. Para duplicar uma linha C-a M-w C-y C-y C-y ...,.


3

- Eu escrevi minha própria versão duplicate-line, porque não quero estragar o anel da 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

Gostei da versão do FraGGod, exceto por duas coisas: (1) Ele não verifica se o buffer já está somente leitura (interactive "*")e (2) falha na última linha do buffer se essa última linha estiver vazia (como você não pode eliminar a linha nesse caso), deixando seu buffer somente leitura.

Fiz as seguintes alterações para resolver isso:

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

3

Com o emacs recente, você pode usar Mw em qualquer lugar da linha para copiá-lo. Então se torna:

M-w C-a RET C-y

Realmente? Qual Emacs "recente" seria esse? Não é o caso de 24.4: você obtém "A marca não está definida agora, portanto não há região".
Davor Cubranic

o Emacs atual é 24,5 e M-westá vinculado a easy-kill. Verifique se é o que você começa quando você fazC-h c M-w
Louis Kottmann

Não funcionou no Emacs 24.5.1. Copiado apenas do início da linha para o ponto no início da mesma linha após inserir uma linha em branco anterior.
Derek Mahar

3

Eu vi soluções muito complexas, de qualquer maneira ...

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

Note que isso vai mexer com o anel de morte.
Dodgie

Isso acrescenta a linha para si mesmo quando é a última linha eo arquivo não termina em uma nova linha
Mark

2

@ [Kevin Conner]: Bem perto, até onde eu sei. A única outra coisa a considerar é ativar kill-whole-linea inclusão da nova linha no Ck.


@Allen: remove [and ]in@[Kevin Conner]
jfs

2

ctrl- k, ctrl- k, (posição para o novo local) ctrl-y

Adicione a ctrl- ase você não estiver começando no início da linha. E o segundo ctrl- ké pegar o personagem nova linha. Pode ser removido se você quiser apenas o texto.


Esse deve ser o método mais direto aqui. Obrigado!
bartlomiej.n

2

Quando chamado interativamente sem região ativa, COPY (Mw) uma única linha:

(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 chamado interativamente sem região ativa, KILL (Cw) uma única linha.

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

Além disso, em uma nota relacionada:

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

1

Eu escrevo um para minha preferência.

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

Mas eu achei que isso teria algum problema quando a linha atual contiver caracteres de vários bytes (por exemplo, caracteres CJK). Se você encontrar esse problema, tente o seguinte:

(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

Essa funcionalidade deve corresponder à implementação do JetBrains em termos de duplicação por linha ou região e, em seguida, deixar o ponto e / ou região ativa conforme o esperado:

Apenas um wrapper para o formulário interativo:

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

O que chama isso,

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

(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 então eu tenho isso vinculado a meta + shift + d

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

1

Como mencionado em outras respostas, vincular pressionamentos de tecla ao código lisp é uma idéia melhor do que vinculá-los a outros pressionamentos de tecla. Com a resposta de @ mw, o código duplica a linha e move a marca para o final da nova linha. Essa modificação mantém a posição da marca na mesma coluna na nova linha:

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

1

Se você estiver usando o Spacemacs, pode simplesmente usar duplicate-line-or-region, vinculado a:

SPC x l d 

0

Com argumentos de prefixo e qual é (espero) 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))))))

O cursor permanecerá na última linha. Como alternativa, convém especificar um prefixo para duplicar as próximas linhas ao mesmo tempo:

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

Encontro-me usando os dois com freqüência, usando uma função de invólucro para mudar o comportamento do argumento do prefixo.

E uma combinação de teclas: (global-set-key (kbd "C-S-d") 'duplicate-line)


0
;; 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.

adicione o elisp acima a você init.el, e você terá a função de cortar / copiar toda a linha agora, então você pode F3 F4 para duplicar uma linha.


0

A maneira mais simples é o método de Chris Conway.

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

Essa é a maneira padrão exigida pelo EMACS. Na minha opinião, é melhor usar o padrão. Sempre sou cuidadoso com a personalização das próprias vinculações de chaves no EMACS. O EMACS já é poderoso o suficiente, acho que devemos tentar o nosso melhor para nos adaptar às suas próprias combinações de teclas.

Embora seja um pouco demorado, mas quando você está acostumado, você pode fazer rápido e achar isso divertido!


4
Considerando tudo, o Emacs exige muito pouco - a grande vitória que ele oferece é a facilidade de personalizá- lo para suas próprias necessidades. Claro que na prática não são muitas maneiras padrão de fazer as coisas que é benéfico para manter, mas se você estiver usando o "default" Emacs e fazer algo de maneira mais difícil do que o necessário apenas porque você acha que "é melhor usar o padrão" , você está praticamente fazendo errado.
phils

0

Aqui está uma função para duplicar a linha atual. Com argumentos de prefixo, duplicará a linha várias vezes. Por exemplo, C-3 C-S-oduplicará a linha atual três vezes. Não muda o anel da morte.

(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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.