Uccidi o copia la riga corrente con sequenze di tasti minime


32

Faccio C-a C-k C-kper uccidere l'intero punto della linea è attivo.

Se voglio copiare la linea invece di ucciderla, posso colpire C-/ C-/ subito dopo aver digitato la sequenza sopra.

In alternativa, posso farlo C-a C-SPC C-n M-w.

C'è un modo più veloce per uccidere o copiare l'intero punto della linea è attivo?


1
Wow! Queste risposte mostrano le lunghezze che le persone faranno per evitare di usare il built-in kill-whole-line. :)
Omar,

Come suggerito di seguito, utilizzare evil-mode. Impara i comandi di Vim, non te ne pentirai!
A. Blizzard,

Risposte:


44

Puoi usare kill-whole-lineper uccidere l'intero punto della linea è attivo. La posizione del punto non ha importanza. Questo comando è associato per C-S-DELimpostazione predefinita.

Puoi anche indicare kill-line(associato a C-k) di eliminare l'intera riga impostando la variabile kill-whole-line su un nilvalore non :

(setq kill-whole-line t)

Si noti che il punto deve essere all'inizio della riga affinché funzioni.


Poi ci sono queste due gemme (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)))))

Con questi in atto è possibile uccidere o copiare il punto di linea è attivo con un solo tasto :

  • C-w uccide la linea corrente
  • M-w copia la riga corrente

Nota che se esiste una regione attiva kill-regione kill-ring-savecontinuerà a fare ciò che fa normalmente: uccidila o copiala.


Porting slick-cute slick-copynuovo sistema di consulenza

Emacs 24.4 introduce un nuovo sistema di consulenza . Mentre defadvice funziona ancora , c'è la possibilità che possa essere deprecato a favore del nuovo sistema nelle versioni future di Emacs. Per prepararti a ciò, potresti voler utilizzare versioni aggiornate di 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)

2
Si noti che kill-regione kill-ring-saveancora il lavoro, anche quando la regione non è "attivo". Questo sovrascriverà quel comportamento. Di tanto in tanto uso quel comportamento, ma se non sei abituato ad usarli in questo modo, probabilmente non noterai la differenza.
nispio,

@nispio Espandi quando / come kill-regionecc è utilizzabile / utile quando lo mark-activeè nil.
Phil Hudson,

1
@PhilHudson Il segno può essere (e di solito è) impostato senza essere attivo. Prova a fare C-SPCdue volte per attivare e quindi disattivare il segno. Sposta il cursore altrove nel file ed esegui kill-regione ucciderà la regione tra punto e segno, anche se il segno non è attivo. Alcuni esempi di comandi che impostano (ma non attivano) il segno sono yanke isearch. Dopo aver eseguito questi comandi di sorta, so dove si trova il segno, anche se non è attivo, e molti comandi (incluso kill-region) mi permetteranno di usare il segno senza attivarlo esplicitamente.
nispio,

Grazie @nispio. Ovviamente. Ecco come era, esclusivamente, prima che l'evidenziazione della regione visibile diventasse di default un paio di importanti rilasci, giusto? Stavo confondendo "attivo" con "set".
Phil Hudson,

1
Questa è la risposta più grande mai pubblicata su qualsiasi SX. Sul serio.
Benjamin Lindqvist,

15

La soluzione che ho trovato per me è usare gli argomenti prefisso.

Per me uccidere mezza linea è una caratteristica utile, ma voglio anche un modo più semplice di uccidere intere linee. Così l'ho fatto in modo che kill-lineuccidesse tutto ciò che era in vista quando veniva dato un argomento prefisso.

(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 questa piccola macro, C-kuccide ancora da un punto, ma C-3 C-kingoia tre linee intere. Come bonus, otteniamo il kill-whole-linecomportamento facendo C-1 C-k.


È un'ottima idea, grazie per averla condivisa! :) Come adatteresti questa soluzione al lavoro per copiare una o più linee? kill-ring-savenon accetta argomenti prefisso ...
itsjeyd

@itsjeyd Sono sicuro che si potrebbe fare qualcosa di simile per unire le due risposte. Ma ci vorrebbe solo un po 'più di lavoro.
Malabarba,

L'ultima riga si riferisce a paredit-kill. È previsto?
Boccaperta-IT

1
Oh, ok grazie. Tuttavia, non sto ottenendo il comportamento previsto. Se posiziono il puntatore al centro di una linea e premo C-3 Ck, la prima linea non viene completamente uccisa. È così che dovrebbe funzionare o sto facendo qualcosa di sbagliato?
Boccaperta-IT,

1
@Malabarba hai ragione, kill-visual-lineè obbligato a C-k. Lo aggiusterò. Grazie ancora.
Boccaperta-IT,

15

C'è un pacchetto chiamato whole-line-or-regionche avvisa vari comandi integrati in modo che agiscano sulla linea corrente se nessuna regione è attiva, quindi M-wcopierà la linea corrente e C-wla ucciderà, per esempio. Uso il pacchetto da anni e lo trovo indispensabile.

Inoltre, questo pacchetto rende tale che un prefisso numerico indicherà il numero di righe su cui agire, quindi M-2 M-wcopierà due righe. Le altre risposte qui non forniscono questa funzionalità utile.

Ho assunto la manutenzione del pacchetto sul mio account github quando l'autore ha smesso di mantenerlo e non ha risposto.

whole-line-or-region fornisce anche funzionalità per l'aggiunta di questo comportamento a ulteriori comandi, se necessario.


Si prega di presentare un problema MELPA per questo, perché non sono sicuro di cosa intendi: installo questo pacchetto da MELPA tutto il tempo senza problemi.
sanityinc il

9

Questa non è una risposta per gli emacs ortodossi. Se, tuttavia, sei disposto a bestemmiare con evill'editing modale, puoi:

  • dd per linea di uccisione
  • cc per linea di copia

Entrambi possono essere preceduti dal numero di righe da eliminare / copiare (ad esempio, 4cccopieranno le 4 righe successive).


5

Oltre alla risposta di @itsjeyd, posso suggerire queste due funzioni?

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

Quindi, definizioni chiave (probabilmente vorrai adattarle):

(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

Per gentile concessione di ErgoEmacs


Grazie per la tua risposta! Potresti considerare di estenderlo un po 'descrivendo in che modo questi comandi differiscono dalle altre soluzioni pubblicate qui. Sì, questa informazione è disponibile nei documenti, ma non fa male renderla più visibile per i futuri lettori :)
itsjeyd

1
È possibile farlo ma modificarlo come il post @Jonathan qui sotto in modo da prendere prima il sexp o la parola e poi prendere la linea se richiamato?
J Spen,

@JSpen Quello che sto facendo è assegnare un tasto di scelta rapida alla funzione. Quello che Jonathan sta facendo è definire un consiglio per una funzione. Quindi, puoi semplicemente consigliare la funzione, quindi definire un tasto di scelta rapida per la funzione consigliata; e avrai il tuo risultato.
Ci

4

Come estensione alla risposta di @ itsjeyd sopra ho quanto segue. (Probabilmente la logica potrebbe essere leggermente ripulita e lo farò quando eseguo il porting sul nuovo sistema di consulenza, probabilmente lo estenderò anche per estenderlo a sexp/ paragraphse ripetuto di nuovo).

Un iniziale C-w/ M-wprenderà solo la parola nel punto, mentre chiamandola una seconda volta prenderà l'intera linea.

;; *** 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)))))))

Hai aggiornato questo e in tal caso dov'è una copia? Inoltre, questo aggiunge una tonnellata di segni all'anello dei segni. Può solo aggiungere un segno all'inizio di dove è stato copiato. Quindi l'inizio della parola o l'inizio della riga. Ora aggiunge come quattro segni ogni volta che è fastidioso. In realtà l'ho cambiato per usare (backward-sexp) ma a volte non riesce a trovarne uno e dà un errore. Può semplicemente copiare la riga se non ne trova una? Non ero sicuro di come farlo o semplicemente ignorare l'errore e non fare rumore. Mi dispiace, non sono il migliore a Lisp.
J Spen,

1

Dato che vuoi farlo con un numero minimo di tasti, puoi usare l'eccellente pacchetto di accordi di David Andersson . Un "accordo di chiave" è due tasti premuti contemporaneamente o un singolo tasto premuto due volte.

È possibile associare qualsiasi accordo chiave a tali funzioni.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "dd"  'kill-whole-line)
(key-chord-define-global "cc"  'yank-whole-line)

Grazie per la risposta :) Ho provato gli accordi chiave un paio di volte in passato e non potevo davvero abituarmi. Ma questa è sicuramente un'utile aggiunta al set se le risposte raccolte qui!
itsjeyd

1

Un modo meno ad-hoc è definire mark-whole-line, per cui Emacs dovrebbe avere un comando predefinito.

(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

Quindi C-2 C-wfarà il lavoro.

Inoltre semplifica le cose come commentare l'intera riga corrente.


0

Questa è una modifica della risposta di itsjeyd - attualmente la risposta più votata e che ho usato per anni. Tuttavia, ha dei problemi: la versione consigliata di kill-ring-savequalche volta fallirebbe perché il segno non è impostato (in genere in un nuovo buffer), e anche quando ha funzionato, il cursore ha fatto una strana danza dopo l'uso della funzione per copiare una singola riga . Dopo alcuni scavi, mi sono reso conto che ciò accade perché le kill-ring-savechiamate indicate-copied-regiondopo che ha fatto il suo lavoro, ma come punto e segno non corrispondono alla regione copiata, hanno indicate-copied-regioncontrassegnato la regione sbagliata.

È stato detto abbastanza. Ecco una soluzione che risolve questo problema:

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

Non c'è nulla di sbagliato nel consiglio di itsjeyd kill-region. Eccone comunque una variante, stilisticamente più coerente con quanto sopra:

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

Nota che se transient-mark-modenon è attivo, questi consigli non fanno nulla.


Se si desidera una soluzione più completa, considerare whole-line-or-regioninvece l'utilizzo del pacchetto ; vedi la risposta di @sanityinc.
Harald Hanche-Olsen,

0

Uso un pacchetto chiamato composable.el . La cosa bella del pacchetto è che modifica Mw e Cw (comandi di copia e uccisione) in modo che siano più simili a Vim, dato che accetta invece i tradizionali comandi emacs. Quindi C-w luccide un'intera linea. Ma puoi anche fare cose come C-w M->uccidere la fine del file. Entrambi i comandi funzionano normalmente quando si contrassegna una regione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.