Mate ou copie a linha atual com o mínimo de pressionamentos de tecla

32

Eu faço C-a C-k C-kpara matar todo o ponto de linha está ligado.

Se eu quiser copiar a linha em vez de matá-la, posso pressionar C-/ C-/ logo após digitar a sequência acima.

Alternativamente, eu posso fazer C-a C-SPC C-n M-w.

Existe uma maneira mais rápida de eliminar ou copiar todo o ponto de linha?

itsjeyd
fonte
1
Uau! Essas respostas mostram os grandes comprimentos que as pessoas fazem para evitar o uso do built-in kill-whole-line. :)
Omar
Como sugerido abaixo, use evil-mode. Aprenda comandos Vim, você não vai se arrepender!
A. Blizzard

Respostas:

44

Você pode usar kill-whole-linepara matar o ponto de linha inteiro. A posição do ponto não importa. Este comando está vinculado C-S-DELpor padrão.

Você também pode instruir kill-line(vinculado a C-k) a eliminar a linha inteira definindo a variável kill-whole-line como um nilvalor não :

(setq kill-whole-line t)

Observe que o ponto deve estar no início da linha para que isso funcione.


Depois, existem essas duas jóias (via emacs-fu ):

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

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

Com estes no lugar, você pode matar ou copiar o ponto de linha está ligado com um único toque de tecla :

  • C-w mata a linha atual
  • M-w copia a linha atual

Observe que se houver uma região ativa kill-regione kill-ring-savecontinuar fazendo o que normalmente fazem: Mate ou copie-a.


Portando slick-cute slick-copypara o novo sistema de aconselhamento

O Emacs 24.4 introduz um novo sistema de aconselhamento . Enquanto defadvice ainda funciona , há uma chance de que ele seja descontinuado em favor do novo sistema em versões futuras do Emacs. Para se preparar para isso, convém usar versões atualizadas slick-cute slick-copy:

(defun slick-cut (beg end)
  (interactive
   (if mark-active
       (list (region-beginning) (region-end))
     (list (line-beginning-position) (line-beginning-position 2)))))

(advice-add 'kill-region :before #'slick-cut)

(defun slick-copy (beg end)
  (interactive
   (if mark-active
       (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position) (line-beginning-position 2)))))

(advice-add 'kill-ring-save :before #'slick-copy)
itsjeyd
fonte
2
Observe que kill-regione kill-ring-saveainda funciona mesmo quando a região não está "ativa". Isso substituirá esse comportamento. Uso esse comportamento de tempos em tempos, mas se você não está acostumado a usá-los dessa maneira, provavelmente não perceberá a diferença.
Nispio
@nispio Por favor, expanda quando / como kill-regionetc é utilizável / útil quando mark-activeé nil.
Phil Hudson
1
@PhilHudson A marca pode ser (e geralmente é) definida sem estar ativa. Tente fazer C-SPCduas vezes para ativar e desativar a marca. Mova o cursor para outro local do arquivo e execute kill-regione ele matará a região entre ponto e marca, mesmo que a marca não esteja ativa. Alguns exemplos de comandos que definem (mas não ativam) a marca são yanke isearch. Depois de executar esses comandos de classificação, sei onde está a marca, mesmo que ela não esteja ativa, e muitos comandos (inclusive kill-region) me permitem usar a marca sem ativá-la explicitamente.
Nispio 31/10/16
Obrigado @nispio. Claro. É assim que costumava ser, exclusivamente, antes que o destaque visível da região se tornasse o padrão em alguns lançamentos importantes, certo? Eu estava confundindo "ativo" com "conjunto".
Phil Hudson
1
Esta é a melhor resposta já publicada em qualquer SX. A sério.
Benjamin Lindqvist 10/10
15

A solução que encontrei para mim é usar argumentos de prefixo.

Para mim, matar meia linha é um recurso útil, mas também quero uma maneira mais fácil de matar linhas inteiras. Então eu fiz isso para que kill-lineapenas assassinasse tudo à vista quando recebesse um argumento de prefixo.

(defmacro bol-with-prefix (function)
  "Define a new function which calls FUNCTION.
Except it moves to beginning of line before calling FUNCTION when
called with a prefix argument. The FUNCTION still receives the
prefix argument."
  (let ((name (intern (format "endless/%s-BOL" function))))
    `(progn
       (defun ,name (p)
         ,(format 
           "Call `%s', but move to BOL when called with a prefix argument."
           function)
         (interactive "P")
         (when p
           (forward-line 0))
         (call-interactively ',function))
       ',name)))

(global-set-key [remap paredit-kill] (bol-with-prefix paredit-kill))
(global-set-key [remap org-kill-line] (bol-with-prefix org-kill-line))
(global-set-key [remap kill-line] (bol-with-prefix kill-line))
(global-set-key "\C-k" (bol-with-prefix kill-line))

Com esta pequena macro, C-kainda mata do ponto, mas C-3 C-kengole três linhas inteiras. Como bônus, obtemos o kill-whole-linecomportamento fazendo C-1 C-k.

Malabarba
fonte
É uma ótima ideia, obrigado por compartilhá-la! :) Como você adaptaria esta solução para trabalhar para copiar uma ou mais linhas? kill-ring-savenão aceita argumentos de prefixo ...
itsjeyd
@itsjeyd Tenho certeza de que algo semelhante pode ser feito para mesclar as duas respostas. Mas seria preciso um pouco mais de trabalho.
Malabarba
A última linha refere-se a paredit-kill. É pretendido?
Boccaperta-IT
1
Ah, tudo bem, obrigado. Não estou conseguindo o comportamento esperado. Se eu colocar o ponteiro no meio de uma linha e pressionar C-3 Ck, a primeira linha não será totalmente eliminada. É assim que deveria estar funcionando ou estou fazendo algo errado?
Boccaperta-IT
1
@ Malabarba você está certo, kill-visual-lineé obrigado a C-k. Eu resolvo isso. Obrigado novamente.
Boccaperta-IT
15

Há um pacote chamado whole-line-or-regionque aconselha vários comandos internos para que eles ajam na linha atual se nenhuma região estiver ativa; portanto M-w, copie a linha atual e C-wa mate, por exemplo. Uso o pacote há anos e o considero indispensável.

Além disso, este pacote faz com que um prefixo numérico indique o número de linhas para atuar, assim M-2 M-wcopia duas linhas. As outras respostas aqui não fornecem essa funcionalidade útil.

Eu assumi a manutenção do pacote na minha conta do github quando o autor parou de mantê-lo e deixou de responder.

whole-line-or-region também fornece recursos para adicionar esse comportamento a outros comandos, caso você precise.

sanityinc
fonte
Por favor, registre um problema MELPA, porque não tenho certeza do que você quer dizer: eu instalo este pacote do MELPA o tempo todo, sem problemas.
Sanityinc # 25/18
9

Esta não é uma resposta para os emacs ortodoxos. Se, no entanto, você estiver disposto a blasfemar com evila edição modal, você pode:

  • dd para matar linha
  • cc para linha de cópia

Ambos podem ser prefixados pelo número de linhas para matar / copiar (por exemplo, 4cccopiará as próximas 4 linhas).

Dan
fonte
5

Além da resposta @itsjeyd, posso sugerir essas duas funções?

(defun xah-copy-line-or-region ()
  "Copy current line, or text selection.
When `universal-argument' is called first, copy whole buffer (but respect `narrow-to-region')."
  (interactive)
  (let (p1 p2)
    (if (null current-prefix-arg)
        (progn (if (use-region-p)
                   (progn (setq p1 (region-beginning))
                          (setq p2 (region-end)))
                 (progn (setq p1 (line-beginning-position))
                        (setq p2 (line-end-position)))))
      (progn (setq p1 (point-min))
             (setq p2 (point-max))))
    (kill-ring-save p1 p2)))

(defun xah-cut-line-or-region ()
  "Cut current line, or text selection.
When `universal-argument' is called first, cut whole buffer (but respect `narrow-to-region')."
  (interactive)
  (let (p1 p2)
    (if (null current-prefix-arg)
        (progn (if (use-region-p)
                   (progn (setq p1 (region-beginning))
                          (setq p2 (region-end)))
                 (progn (setq p1 (line-beginning-position))
                        (setq p2 (line-beginning-position 2)))))
      (progn (setq p1 (point-min))
             (setq p2 (point-max))))
    (kill-region p1 p2)))

Em seguida, definições principais (provavelmente você as adaptará):

(global-set-key (kbd "<f2>") 'xah-cut-line-or-region) ; cut

(global-set-key (kbd "<f3>") 'xah-copy-line-or-region) ; copy

(global-set-key (kbd "<f4>") 'yank) ; paste

Cortesia de ErgoEmacs

Nsukami _
fonte
Obrigado pela sua resposta! Convém estender um pouco, descrevendo como esses comandos diferem de outras soluções postadas aqui. Sim, esta informação está disponível nas docstrings, mas não faz mal para torná-lo mais visível para futuros leitores :)
itsjeyd
1
É possível fazer isso, mas modifique-o como a postagem de Jonathan abaixo, para que primeiro pegue o sexp ou a palavra e depois pegue a linha se for chamado novamente?
J Spen
@JSpen O que estou fazendo é atribuir uma tecla de atalho para funcionar. O que Jonathan está fazendo é definir um conselho para uma função. Portanto, você pode apenas aconselhar a função e definir uma tecla de atalho para a função recomendada; e você terá o seu resultado. Desculpe pelo atraso;)
Nsukami _ 15/01
4

Como extensão à resposta de @ itsjeyd acima, tenho o seguinte. (A lógica provavelmente pode ser um pouco limpa, e quando eu for para o novo sistema de aconselhamento, provavelmente a estenderei também para estender sexp/ paragraphse repetir novamente).

Uma inicial C-w/ M-wpegará apenas a palavra no momento, enquanto a chama uma segunda vez pegará a linha inteira.

;; *** Copy word/line without selecting
(defadvice kill-ring-save (before slick-copy-line activate compile)
  "When called interactively with no region, copy the word or line

Calling it once without a region will copy the current word.
Calling it a second time will copy the current line."
    (interactive
     (if mark-active (list (region-beginning) (region-end))
       (if (eq last-command 'kill-ring-save)
           (progn
             ;; Uncomment to only keep the line in the kill ring
             ;; (kill-new "" t)
             (message "Copied line")
             (list (line-beginning-position)
                   (line-beginning-position 2)))
         (save-excursion
           (forward-char)
           (backward-word)
           (mark-word)
           (message "Copied word")
           (list (mark) (point)))))))

;; *** Kill word/line without selecting
(defadvice kill-region (before slick-cut-line first activate compile)
  "When called interactively kill the current word or line.

Calling it once without a region will kill the current word.
Calling it a second time will kill the current line."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
    (if (eq last-command 'kill-region)
        (progn
          ;; Return the previous kill to rebuild the line
          (yank)
          ;; Add a blank kill, otherwise the word gets appended.
          ;; Change to (kill-new "" t) to remove the word and only
          ;; keep the whole line.
          (kill-new "")
          (message "Killed Line")
          (list (line-beginning-position)
                (line-beginning-position 2)))
      (save-excursion
        (forward-char)
        (backward-word)
        (mark-word)
        (message "Killed Word")
        (list (mark) (point)))))))
Jonathan Leech-Pepin
fonte
Você atualizou isso e, em caso afirmativo, onde está uma cópia? Além disso, isso adiciona uma tonelada de marcas ao anel de marcas. Pode apenas adicionar uma marca no início de onde copiou. Então, o começo da palavra ou o começo da linha. Agora, ele adiciona quatro marcas todas as vezes, o que é irritante. Na verdade, eu mudei para usar (backward-sexp), mas às vezes ele não consegue encontrar um e gera um erro. Pode apenas copiar a linha se não encontrar uma? Eu não tinha certeza de como fazer isso ou simplesmente ignore o erro e não faça barulho. Desculpe, eu não sou o melhor em lisp.
precisa
1

Como você deseja fazer isso com o mínimo de pressionamentos de teclas, pode usar o excelente pacote de acordes de teclas de David Andersson . Um "acorde de teclas" consiste em duas teclas pressionadas simultaneamente ou uma única tecla pressionada duas vezes.

Você pode vincular quaisquer acordes de teclas a essas funções.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "dd"  'kill-whole-line)
(key-chord-define-global "cc"  'yank-whole-line)
ChillarAnand
fonte
Obrigado pela sua resposta :) Eu tentei acordes de teclas algumas vezes no passado e não consegui me acostumar com eles. Mas essa é definitivamente uma adição útil ao conjunto, se as respostas forem coletadas aqui!
itsjeyd 19/09/15
1

Uma maneira menos ad-hoc é definir mark-whole-line, para o qual o Emacs realmente deve ter um comando padrão.

(defun mark-whole-line ()               
    "Combinition of C-a, mark, C-e"
    (interactive)
    (move-beginning-of-line nil)
    (set-mark-command nil)
    (move-end-of-line nil)
)
(global-set-key (kbd "C-2") 'mark-whole-line) ; 2 is near w

Então C-2 C-wfará o trabalho.

Isso também facilita as coisas, como comentar toda a linha atual.

Cromático
fonte
0

Esta é uma modificação da resposta por itsjeyd - atualmente a resposta mais votada e que eu uso há anos. No entanto, há problemas: a versão recomendada de kill-ring-savealgum dia falharia porque a marca não está definida (normalmente em um novo buffer) e, mesmo quando funcionava, o cursor fazia uma dança estranha após o uso da função para copiar uma única linha . Depois de algumas escavações, percebi que isso acontece porque as kill-ring-savechamadas indicate-copied-regionapós o término de seu trabalho, mas como ponto e marca não correspondem à região copiada, indicate-copied-regionmarcaram a região errada.

Disse o suficiente. Aqui está uma solução que resolve isso:

(define-advice kill-ring-save
    (:before-while (beg end &optional region) slick)
  (or mark-active
      (not (called-interactively-p 'interactive))
      (prog1 nil
    (copy-region-as-kill
     (line-beginning-position) (line-beginning-position 2))
    (message "Copied current line"))))

Não há nada de errado com os conselhos de itsjeyd kill-region. De qualquer forma, aqui está uma variante, estilisticamente mais consistente com o acima:

(define-advice kill-region
    (:around (kill-region beg end &optional region) slick)
  (if (or mark-active (not region))
      (funcall kill-region beg end region)
    (funcall kill-region
             (line-beginning-position) (line-beginning-position 2))
    (message "Killed current line")))

Observe que, se transient-mark-modenão estiver ativado, esses conselhos não farão nada.

Harald Hanche-Olsen
fonte
Se você deseja uma solução mais abrangente, considere usar o pacote whole-line-or-region; veja a resposta de @sanityinc.
Harald Hanche-Olsen
0

Eu uso um pacote chamado composable.el . O mais interessante do pacote é que ele modifica Mw e Cw (comandos copy e kill) para serem mais parecidos com o Vim, com a opção de aceitar comandos tradicionais do emacs. Então C-w lmata uma linha inteira. Mas você também pode fazer coisas como C-w M->matar o final do arquivo. Ambos os comandos agem como normais ao marcar uma região.

Greth
fonte