Mata o copia la línea actual con un mínimo de pulsaciones de teclas

32

Lo hago C-a C-k C-kpara matar todo el punto de línea está encendido.

Si quiero copiar la línea en lugar de matarla, puedo presionar C-/ C-/ justo después de escribir la secuencia anterior.

Alternativamente, puedo hacer C-a C-SPC C-n M-w.

¿Hay una forma más rápida de matar o copiar todo el punto de línea?

itsjeyd
fuente
1
¡Guauu! Estas respuestas muestran los grandes esfuerzos que las personas harán para evitar el uso de las funciones integradas kill-whole-line. :)
Omar
Como se sugiere a continuación, use evil-mode. Aprende los comandos de Vim, ¡no te arrepentirás!
A. Blizzard

Respuestas:

44

Puede usar kill-whole-linepara matar todo el punto de línea está activado. La posición del punto no importa. Este comando está vinculado C-S-DELde forma predeterminada.

También puede indicar kill-line(vinculado a C-k) que elimine toda la línea estableciendo la variable kill-whole-line en un nilvalor no :

(setq kill-whole-line t)

Tenga en cuenta que el punto tiene que estar al principio de la línea para que esto funcione.


Luego están estas dos gemas (a través de 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)))))

Con estos en su lugar, puede matar o copiar el punto de línea con solo presionar una tecla :

  • C-w mata la línea actual
  • M-w copia la línea actual

Tenga en cuenta que si hay una región activa kill-regiony kill-ring-savecontinuará haciendo lo que normalmente hacen: matarla o copiarla.


Portabilidad slick-cuty slick-copynuevo sistema de asesoramiento

Emacs 24.4 presenta un nuevo sistema de asesoramiento . Si bien defadvice aún funciona , existe la posibilidad de que quede obsoleto a favor del nuevo sistema en futuras versiones de Emacs. Para prepararse para eso, es posible que desee utilizar versiones actualizadas de slick-cuty 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
fuente
2
Tenga en cuenta que kill-regiony kill-ring-savetodavía trabajo, incluso cuando la región no es "activo". Esto anulará ese comportamiento. Uso ese comportamiento de vez en cuando, pero si no estás acostumbrado a usarlos de esta manera, entonces probablemente no notarás la diferencia.
nispio
@nispio Expanda cuándo / cómo, kill-regionetc., es útil / útil cuando lo mark-activees nil.
Phil Hudson
1
@PhilHudson La marca se puede establecer (y generalmente se establece) sin estar activa. Intente hacer C-SPCdos veces para activar y luego desactivar la marca. Mueva el cursor a otra parte del archivo y ejecútelo, kill-regiony matará la región entre el punto y la marca, aunque la marca no esté activa. Algunos ejemplos de comandos que establecen (pero no activan) la marca son yanky isearch. Después de realizar estos comandos de clasificación, sé dónde está la marca, incluso si no está activa, y muchos comandos (incluidos kill-region) me permitirán usar la marca sin activarla explícitamente.
nispio
Gracias @nispio. Por supuesto. Así solía ser, exclusivamente, antes de que el resaltado de la región visible se convirtiera en el predeterminado por un par de lanzamientos importantes, ¿verdad? Estaba confundiendo "activo" con "conjunto".
Phil Hudson el
1
Esta es la mejor respuesta jamás publicada en cualquier SX. Seriamente.
Benjamin Lindqvist
15

La solución que he encontrado para mí es usar argumentos de prefijo.

Para mí, matar media línea es una característica útil, pero también quiero una forma más fácil de matar líneas enteras. Así que lo hice para que kill-linesimplemente asesine todo a la vista cuando se le da un argumento de prefijo.

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

Con esta pequeña macro, C-ktodavía mata desde el punto, pero se C-3 C-ktraga tres líneas enteras. Como beneficio adicional, obtenemos el kill-whole-linecomportamiento haciendo C-1 C-k.

Malabarba
fuente
Esa es una gran idea, ¡gracias por compartirla! :) ¿Cómo adaptaría esta solución al trabajo para copiar una o más líneas? kill-ring-saveno acepta argumentos de prefijo ...
itsjeyd
@itsjeyd Estoy seguro de que se podría hacer algo similar para fusionar las dos respuestas. Pero tomaría un poco más de trabajo.
Malabarba
La última línea se refiere a paredit-kill. ¿Está destinado?
Boccaperta-IT
1
Oh vale gracias. Sin embargo, no estoy obteniendo el comportamiento esperado. Si coloco el puntero en el medio de una línea y presiono C-3 Ck, la primera línea no se elimina por completo. ¿Es así como se supone que funciona o estoy haciendo algo mal?
Boccaperta-IT
1
@Malabarba tienes razón, kill-visual-lineestá obligado a C-k. Lo arreglaré. Gracias de nuevo.
Boccaperta-IT
15

Hay un paquete llamado whole-line-or-regionque aconseja varios comandos integrados para que actúen en la línea actual si no hay una región activa, por M-wlo que copiará la línea actual y la C-wmatará, por ejemplo. He estado usando el paquete durante años, y lo encuentro indispensable.

Además, este paquete hace que un prefijo numérico indique el número de líneas sobre las que actuar, por M-2 M-wlo que copiará dos líneas. Las otras respuestas aquí no proporcionan esa práctica funcionalidad.

Me hice cargo del mantenimiento del paquete en mi cuenta de github cuando el autor dejó de mantenerlo y dejó de responder.

whole-line-or-region también proporciona facilidades para agregar este comportamiento a otros comandos, en caso de que lo necesite.

sanityinc
fuente
Presente un problema de MELPA para eso, porque no estoy seguro de lo que quiere decir: instalo este paquete de MELPA todo el tiempo sin problemas.
sanityinc
9

Esta no es una respuesta para los emacs ortodoxos. Sin embargo, si está dispuesto a blasfemar con evilla edición modal, puede:

  • dd para línea de matar
  • cc para línea de copia

Ambos pueden tener el prefijo por el número de líneas para matar / copiar (por ejemplo, 4cccopiará las siguientes 4 líneas).

Dan
fuente
5

Además de la respuesta de @itsjeyd, ¿puedo sugerir esas dos funciones?

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

Luego, las definiciones clave (probablemente querrás adaptarlas):

(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

Cortesía de ErgoEmacs.

Nsukami _
fuente
¡Gracias por tu respuesta! Es posible que desee considerar extenderlo un poco describiendo cómo estos comandos difieren de otras soluciones publicadas aquí. Sí, esta información está disponible en las cadenas de documentos, pero no está de más hacerla más visible para futuros lectores :)
itsjeyd
1
¿Es posible hacer esto pero modificarlo como @Jonathan post a continuación para que primero tome el sexp o la palabra y luego tome la línea si se llama nuevamente?
J Spen
@JSpen Lo que estoy haciendo es asignar una tecla de acceso directo para funcionar. Lo que Jonathan está haciendo es definir un consejo para una función. Por lo tanto, puede simplemente aconsejar la función, luego definir una tecla de acceso directo a la función recomendada; y tendrás tu resultado. Perdón por el retraso;)
Nsukami _
4

Como una extensión de la respuesta de @ itsjeyd anterior, tengo lo siguiente. (La lógica probablemente podría limpiarse un poco y lo haré cuando transfiera al nuevo sistema de consejos, probablemente también lo extienda para extender sexp/ paragraphsi se repite nuevamente).

Un C-w/ inicial M-wtomará solo la palabra en el punto, mientras que llamarla por segunda vez tomará toda la línea.

;; *** 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
fuente
¿Actualizó esto y, de ser así, dónde hay una copia? Además, esto agrega un montón de marcas al anillo de marcas. ¿Puede simplemente agregar una marca al comienzo de donde se copió? Entonces, el comienzo de la palabra o el comienzo de la línea. Ahora agrega como cuatro marcas cada vez que es molesto. De hecho, lo he cambiado para usar (backward-sexp) pero a veces no puede encontrar uno y da un error. ¿Puede copiar la línea si no encuentra una? No estaba seguro de cómo hacer esto o simplemente ignorar el error y no hacer ruido. Lo siento, no soy el mejor en lisp.
J Spen
1

Como desea hacerlo con un mínimo de pulsaciones de teclas, puede utilizar el excelente paquete de acordes de teclas de David Andersson . Un "acorde de teclas" es dos teclas presionadas simultáneamente, o una sola tecla presionada dos veces.

Puede vincular cualquier acorde clave a esas funciones.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "dd"  'kill-whole-line)
(key-chord-define-global "cc"  'yank-whole-line)
ChillarAnand
fuente
Gracias por su respuesta :) Intenté acordes clave un par de veces en el pasado y realmente no pude acostumbrarme a ellos. ¡Pero esta es definitivamente una adición útil al conjunto si las respuestas se recopilan aquí!
itsjeyd
1

Una forma menos ad-hoc es definir mark-whole-line, para qué Emacs realmente debería tener un comando predeterminado.

(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

Entonces C-2 C-whará el trabajo.

También facilita las cosas como comentar toda la línea actual.

Cromático
fuente
0

Esta es una modificación de la respuesta de itsjeyd, actualmente la respuesta más votada, y la que he usado durante años. Sin embargo, tiene problemas: la versión recomendada de kill-ring-savealguna vez fallará porque la marca no está establecida (generalmente en un nuevo búfer), e incluso cuando funcionó, el cursor hizo un baile extraño después del uso de la función para copiar una sola línea . Después de investigar un poco, me di cuenta de que esto sucede porque las kill-ring-savellamadas indicate-copied-regiondespués de haber realizado su trabajo, pero como el punto y la marca no coinciden con la región copiada, indicate-copied-regionmarcó la región incorrecta.

Basta de charla. Aquí hay una solución que soluciona esto:

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

No hay nada malo con el consejo de itsjeyd sobre kill-region. Aquí hay una variante de la misma, estilísticamente más consistente con lo anterior:

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

Tenga en cuenta que si transient-mark-modeno está activado, estos consejos no hacen nada.

Harald Hanche-Olsen
fuente
Si desea una solución más completa, considere usar el paquete en su whole-line-or-regionlugar; mira la respuesta de @sanityinc.
Harald Hanche-Olsen
0

Yo uso un paquete llamado composable.el . Lo bueno del paquete es que modifica Mw y Cw (comandos de copiar y matar) para que se parezca más a Vim con el giro que acepta en su lugar los comandos tradicionales de emacs. Entonces C-w lmata una línea entera. Pero también puede hacer cosas como C-w M->matar el final del archivo. Ambos comandos actúan de manera normal al marcar una región.

Greth
fuente