Supprimer ou copier la ligne actuelle en un minimum de frappe


32

Je fais C-a C-k C-kpour tuer toute la ligne point est allumé.

Si je veux copier la ligne au lieu de la tuer, je peux appuyer C-/ C-/ juste après avoir tapé la séquence ci-dessus.

Alternativement, je peux faire C-a C-SPC C-n M-w.

Existe-t-il un moyen plus rapide de supprimer ou de copier le point de ligne entier?


1
Hou la la! Ces réponses montrent les efforts que les utilisateurs devront faire pour éviter d’utiliser l’intégré kill-whole-line. :)
Omar

Comme suggéré ci-dessous, utilisez evil-mode. Apprenez les commandes de Vim, vous ne le regretterez pas!
A. Blizzard

Réponses:


44

Vous pouvez utiliser kill-whole-linepour tuer toute la ligne point est allumé. La position du point n'a pas d'importance. Cette commande est liée à C-S-DELpar défaut.

Vous pouvez également demander kill-line(lié à C-k) de tuer la ligne entière en définissant la variable kill-whole-line sur une nilvaleur autre que:

(setq kill-whole-line t)

Notez que le point doit être au début de la ligne pour que cela fonctionne.


Ensuite, il y a ces deux joyaux (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)))))

Avec ceux-ci en place, vous pouvez supprimer ou copier le point de la ligne en appuyant sur une seule touche :

  • C-w tue la ligne actuelle
  • M-w copie la ligne en cours

Notez que s'il y a une région active kill-regionet kill-ring-savecontinuera à faire ce qu'elle fait normalement: la tuer ou la copier.


Portage slick-cutet slick-copynouveau système de conseil

Emacs 24.4 introduit un nouveau système de conseil . Bien que cela defadvice fonctionne toujours , il est possible qu’il devienne obsolète en faveur du nouveau système dans les futures versions d’Emacs. Pour vous y préparer, vous pouvez utiliser les versions mises à jour de slick-cutet 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
Notez que kill-regionet kill-ring-savefonctionnent toujours même lorsque la région n’est pas "active". Cela annulera ce comportement. J'utilise ce comportement de temps en temps, mais si vous n'êtes pas habitué à les utiliser de cette façon, vous ne remarquerez probablement pas la différence.
nispio

@nispio Veuillez préciser quand / comment kill-regionetc est utilisable / utile quand mark-activeest nil.
Phil Hudson

1
@PhilHudson La marque peut être (et est généralement) définie sans être active. Essayez de faire C-SPCdeux fois pour activer puis désactiver la marque. Déplacez le curseur ailleurs dans le fichier et exécutez kill-region-le. La région entre le point et la marque sera supprimée, même si la marque n'est pas active. Quelques exemples de commandes qui définissent (mais n'activent pas) la marque sont yanket isearch. Après avoir exécuté ces commandes de tri, je sais où se trouve la marque, même si elle n’est pas active, et de nombreuses commandes (y compris kill-region) me permettent d’utiliser la marque sans l’activer explicitement.
nispio

Merci @ nispio. Bien sûr. C’est comme ça que ça se passait, en exclusivité, avant que la mise en évidence des régions visibles ne devienne la règle par défaut quelques versions précédentes, non? Je confondais "actif" avec "set".
Phil Hudson

1
C'est la plus grande réponse jamais publiée sur un SX. Sérieusement.
Benjamin Lindqvist

15

La solution que j'ai trouvée est d'utiliser des arguments de préfixe.

Supprimer une demi-ligne est pour moi une fonctionnalité utile, mais je souhaite également un moyen plus simple de supprimer des lignes entières. J'ai donc fait en sorte que kill-linetout assassine en vue quand on lui donne un argument préfixe.

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

Avec cette petite macro, C-ktue toujours du point, mais C-3 C-kavale trois lignes entières. En prime, nous obtenons le kill-whole-linecomportement en agissant C-1 C-k.


C'est une bonne idée, merci de la partager! :) Comment adapteriez-vous cette solution pour pouvoir copier une ou plusieurs lignes? kill-ring-saven'accepte pas les arguments de préfixe ...
itsjeyd

@itsjeyd Je suis sûr que quelque chose de similaire pourrait être fait pour fusionner les deux réponses. Mais cela prendrait juste un peu plus de travail.
Malabarba

La dernière ligne se réfère à paredit-kill. Est-ce prévu?
Boccaperta-IT

1
Oh, d'accord, merci. Je ne reçois pas le comportement attendu, cependant. Si je place le pointeur au milieu d'une ligne et frappe C-3 Ck, la première ligne n'est pas entièrement détruite. Est-ce ainsi que cela est censé fonctionner ou est-ce que je fais quelque chose de mal?
Boccaperta-IT

1
@Malabarba vous avez raison, kill-visual-lineest lié à C-k. Je le réparerai. Merci encore.
Boccaperta-IT

15

Il y a un paquetage appelé whole-line-or-regionqui conseille diverses commandes intégrées pour qu'elles agissent sur la ligne en cours si aucune région n'est active. Ainsi M-w, la ligne en cours C-wsera copiée et supprimée, par exemple. Je l'utilise depuis des années et je le trouve indispensable.

De plus, ce paquetage fait en sorte qu'un préfixe numérique indique le nombre de lignes sur lesquelles agir, ainsi M-2 M-wcopie deux lignes. Les autres réponses ici ne fournissent pas cette fonctionnalité pratique.

J'ai pris en charge la maintenance du paquet sur mon compte github lorsque l'auteur a cessé de le maintenir et est devenu insensible.

whole-line-or-region fournit également des fonctionnalités pour ajouter ce comportement à d'autres commandes, si vous en avez besoin.


Merci de déposer un problème MELPA pour cela, car je ne suis pas sûr de ce que vous voulez dire: j’installe ce paquet depuis MELPA tout le temps sans problème.
sanityinc

9

Ce n'est pas une réponse pour les Emacs orthodoxes. Si, toutefois, vous êtes prêt à blasphémer avec evill'édition modale, vous pouvez:

  • dd pour tuer ligne
  • cc pour la ligne de copie

Les deux peuvent être préfixés par le nombre de lignes à supprimer / copier (par exemple, 4cccopiera les 4 lignes suivantes).


5

Outre @itsjeyd answer, puis-je suggérer ces deux fonctions?

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

Ensuite, les définitions clés (vous voudrez probablement les adapter):

(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

Gracieuseté de ErgoEmacs


Merci pour votre réponse! Vous voudrez peut-être envisager de l'étendre un peu en décrivant en quoi ces commandes diffèrent des autres solutions publiées ici. Oui, cette information est disponible dans les docstrings, mais cela ne fait pas de mal de le rendre plus visible pour les futurs lecteurs :)
itsjeyd

1
Est-il possible de le faire, mais modifiez-le comme @Jonathan post ci-dessous pour qu'il prenne d'abord le mot sexp ou le mot, puis prend la ligne s'il est appelé à nouveau?
J Spen

@JSpen Ce que je fais est d'attribuer une touche de raccourci à la fonction. Ce que fait Jonathan, c'est définir un conseil pour une fonction. Vous pouvez donc simplement conseiller la fonction, puis définir une touche de raccourci vers la fonction conseillée; et vous aurez votre résultat. Désolé pour le retard;)
Nsukami _

4

En guise de prolongement de la réponse de @ itsjeyd ci-dessus, j'ai les éléments suivants. (La logique pourrait probablement être nettoyé un peu et je vais quand je port au nouveau système de conseils, je vais probablement l' étendre à d' étendre à sexp/ paragraphsi elle est répétée à nouveau).

Une initiale C-w/ M-wne saisira que le mot au point, tandis que l'appelant une seconde fois saisira toute la ligne.

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

L'avez-vous mis à jour et, le cas échéant, où se trouve une copie? En outre, cela ajoute une tonne de marques à l'anneau de marque. Peut-il simplement ajouter une marque au début de l'endroit où il a été copié? Donc, le début du mot ou le début de la ligne. Maintenant, il ajoute environ quatre marques à chaque fois, ce qui est agaçant. En fait, je l'ai changé pour utiliser (backward-sexp) mais parfois, il ne peut pas en trouver un et cela donne une erreur. Peut-il simplement copier la ligne s'il n'en trouve pas? Je ne savais pas trop comment faire cela ou simplement ignorer l'erreur et ne pas faire de bruit. Désolé, je ne suis pas le meilleur au lisp.
J Spen

1

Puisque vous voulez le faire avec un minimum de touches, vous pouvez utiliser l'excellent paquet accords-clés de David Andersson . Un "accord de touche" est deux touches enfoncées simultanément, ou une seule touche enfoncée deux fois.

Vous pouvez lier n'importe quel accord clé à ces fonctions.

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

Merci pour votre réponse :) J'ai essayé plusieurs fois les accords clés et je ne pouvais pas vraiment m'y habituer. Mais c’est certainement un ajout utile à l’ensemble si les réponses sont recueillies ici!
itsjeyd

1

Une méthode moins ad hoc consiste à définir le type de mark-whole-linecommande par défaut pour Emacs.

(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

Ensuite, C-2 C-wfera le travail.

Cela facilite également les choses, comme commenter toute la ligne actuelle.


0

Ceci est une modification de la réponse par itsjeyd - actuellement la réponse la plus votée et celle que j'ai utilisée pendant des années. Cependant, il y a des problèmes: la version conseillée de échouait kill-ring-saveparfois parce que la marque n'était pas définie (généralement dans un nouveau tampon), et même si cela fonctionnait, le curseur faisait une danse étrange après l'utilisation de la fonction pour copier une seule ligne . Après quelques recherches, je me suis rendu compte que cela se produisait parce que les kill-ring-saveappels indicate-copied-regionaprès que celui-ci ait fait son travail, mais comme les points et marques ne correspondent pas à la région copiée, indicate-copied-regionmarquent la mauvaise région.

Assez dit. Voici une solution qui remédie à cela:

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

Il n'y a rien de mal avec les conseils de itsjeyd kill-region. En voici une variante, stylistiquement plus cohérente avec ce qui précède:

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

Notez que si transient-mark-moden’est pas activé, ces conseils ne font rien.


Si vous souhaitez une solution plus complète, envisagez whole-line-or-regionplutôt d' utiliser le package . voir la réponse de @sanityinc.
Harald Hanche-Olsen le

0

J'utilise un package appelé composable.el . La chose intéressante à propos du paquet est qu'il modifie Mw et Cw (commandes de copie et de suppression) pour qu'il soit plus semblable à Vim, mais accepte plutôt les commandes traditionnelles emacs. Donc C-w ltue toute une ligne. Mais vous pouvez aussi faire des choses comme C-w M->tuer la fin du fichier. Les deux commandes agissent normalement lors du marquage d'une région.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.