Zabij lub skopiuj bieżącą linię przy minimalnym naciśnięciu klawisza

32

Robię, C-a C-k C-kżeby zabić cały punkt linii jest włączony.

Jeśli chcę skopiować wiersz zamiast go zabić, mogę uderzyć C-/ C-/ zaraz po wpisaniu powyższej sekwencji.

Alternatywnie mogę to zrobić C-a C-SPC C-n M-w.

Czy istnieje szybszy sposób na zabicie lub skopiowanie całego punktu linii?

itsjeyd
źródło
1
Łał! Te odpowiedzi pokazują, jak wiele osób przejdzie, aby uniknąć korzystania z wbudowanego kill-whole-line. :)
Omar
Jak sugerowano poniżej, użyj evil-mode. Naucz się poleceń Vima, nie pożałujesz!
A. Blizzard

Odpowiedzi:

44

Możesz użyć, kill-whole-lineaby zabić cały punkt linii jest włączony. Pozycja punktu nie ma znaczenia. C-S-DELDomyślnie to polecenie jest powiązane .

Możesz także poinstruować kill-line(powiązanego z C-k) zabić całą linię, ustawiając zmienną kill-whole-line na nilwartość inną niż wartość:

(setq kill-whole-line t)

Zauważ, że punkt musi znajdować się na początku linii, aby to zadziałało.


Są jeszcze dwa klejnoty (przez 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)))))

Po ich wprowadzeniu możesz zabić lub skopiować punkt linii za jednym naciśnięciem klawisza :

  • C-w zabija bieżącą linię
  • M-w kopiuje bieżącą linię

Zauważ, że jeśli istnieje aktywny region kill-regioni kill-ring-savenadal będziesz robić to, co zwykle: zabij lub skopiuj go.


Przeniesienie slick-cuti slick-copydo nowego systemu porad

Emacs 24.4 wprowadza nowy system porad . Chociaż defadvice nadal działa , istnieje szansa, że ​​może być przestarzały na korzyść nowego systemu w przyszłych wersjach Emacsa. Aby się do tego przygotować, możesz użyć zaktualizowanych wersji slick-cuti 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
źródło
2
Należy pamiętać, że kill-regioni kill-ring-savenadal działać nawet wtedy, gdy obszar nie jest „aktywny”. To zastąpi to zachowanie. Od czasu do czasu używam tego zachowania, ale jeśli nie jesteś przyzwyczajony do korzystania z nich w ten sposób, prawdopodobnie nie zauważysz różnicy.
nispio
@nispio Proszę rozwinąć, kiedy / jak kill-regionitp. jest użyteczne / przydatne, kiedy mark-activejest nil.
Phil Hudson
1
@PhilHudson Znak można ustawić (i zwykle jest) bez aktywności. Spróbuj zrobić C-SPCdwa razy, aby aktywować, a następnie dezaktywować znak. Przesuń kursor w inne miejsce pliku i uruchom, kill-regiona to zabije region między punktem i znakiem, nawet jeśli znak nie jest aktywny. Kilka przykładów poleceń, które ustawiają (ale nie aktywują) znak to yanki isearch. Po wykonaniu tych poleceń sortowania wiem, gdzie jest znak, nawet jeśli nie jest aktywny, a wiele poleceń (w tym kill-region) pozwoli mi użyć znaku bez wyraźnej jego aktywacji.
nispio
Dzięki @nispio. Oczywiście. Tak było kiedyś, zanim widoczne podświetlanie regionu stało się domyślną wersją kilku głównych wydań, prawda? Myliłem „aktywny” z „set”.
Phil Hudson,
1
To najlepsza odpowiedź, jaką kiedykolwiek opublikowano na dowolnym SX. Poważnie.
Benjamin Lindqvist,
15

Rozwiązaniem, które znalazłem dla siebie, jest użycie argumentów z przedrostkiem.

Dla mnie zabicie połowy linii jest przydatną funkcją, ale chcę też łatwiejszego sposobu zabijania całych linii. Zrobiłem to, aby kill-linepo prostu mordować wszystko w zasięgu wzroku, gdy podano argument prefiksowy.

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

Z tym małym makro C-knadal zabija od punktu, ale C-3 C-kpołyka trzy całe linie. Jako bonus otrzymujemy takie kill-whole-linezachowanie C-1 C-k.

Malabarba
źródło
To świetny pomysł, dziękuję za udostępnienie! :) Jak dostosowałbyś to rozwiązanie do pracy przy kopiowaniu jednego lub więcej wierszy? kill-ring-savenie akceptuje argumentów z prefiksem ...
itsjeyd
@itsjeyd Jestem pewien, że można zrobić coś podobnego, aby połączyć dwie odpowiedzi. Ale zajmie to trochę więcej pracy.
Malabarba,
Ostatnia linia odnosi się do paredit-kill. Czy to jest zamierzone?
Boccaperta-IT,
1
Oh, ok dzięki. Jednak nie dostaję oczekiwanego zachowania. Jeśli ustawię wskaźnik na środku linii i uderzę C-3 Ck, pierwsza linia nie zostanie całkowicie zabita. Czy tak ma to działać, czy robię coś złego?
Boccaperta-IT,
1
@Malabarba masz rację, kill-visual-linejest zobowiązany do C-k. Naprawię to. Dzięki jeszcze raz.
Boccaperta-IT,
15

Jest tak zwany pakiet, whole-line-or-regionktóry radzi różnym wbudowanym poleceniom, aby działały na bieżącej linii, jeśli żaden region nie jest aktywny, więc M-wskopiują bieżącą linię i C-wna przykład ją zabiją. Korzystam z pakietu od lat i uważam go za niezbędny.

Dodatkowo ten pakiet sprawia, że ​​przedrostek numeryczny będzie wskazywał liczbę linii, na których ma działać, więc M-2 M-wskopiuje dwie linie. Inne odpowiedzi tutaj nie zapewniają tej przydatnej funkcjonalności.

Przejęłem utrzymanie pakietu na moim koncie github, gdy autor przestał go utrzymywać i przestał odpowiadać.

whole-line-or-region zapewnia także możliwości dodawania tego zachowania do dalszych poleceń, jeśli zajdzie taka potrzeba.

sanityinc
źródło
Proszę o zgłoszenie problemu MELPA, ponieważ nie jestem pewien, co masz na myśli: cały czas instaluję ten pakiet z MELPA bez problemów.
sanityinc
9

To nie jest odpowiedź na prawosławne emacsy. Jeśli jednak chcesz bluźnić za pomocą evilmodalnej edycji, możesz:

  • dd dla linii zabicia
  • cc dla linii kopiowania

Oba mogą być poprzedzone liczbą linii do zabicia / skopiowania (np. 4ccSkopiują kolejne 4 linie).

Dan
źródło
5

Oprócz odpowiedzi @itsjeyd, czy mogę zasugerować te dwie funkcje?

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

Następnie kluczowe definicje (prawdopodobnie będziesz chciał je dostosować):

(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

Dzięki uprzejmości ErgoEmacs

Nsukami _
źródło
Dzięki za odpowiedź! Warto rozważyć jego rozszerzenie, opisując, w jaki sposób te polecenia różnią się od innych opublikowanych tutaj rozwiązań. Tak, ta informacja jest dostępna w dokumentach, ale nie szkodzi, aby była bardziej widoczna dla przyszłych czytelników :)
itsjeyd
1
Czy można to zrobić, ale zmodyfikuj go tak, jak @Jonathan poniżej, aby najpierw pobierał seksu lub słowa, a następnie wziął linię, jeśli zostanie wywołany ponownie?
J Spen
@JSpen To, co robię, to przypisanie klawisza skrótu do funkcji. Jonathan określa poradę dla funkcji. Możesz więc po prostu doradzić tej funkcji, a następnie zdefiniować klawisz skrótu do zalecanej funkcji; i będziesz mieć swój wynik. Przepraszamy za opóźnienie;)
Nsukami _
4

Jako rozszerzenie powyższej odpowiedzi @ itsjeyd mam następujące. (Prawdopodobnie logika mogłaby zostać nieco oczyszczona i zrobię to, kiedy przeniesie się do nowego systemu porad, prawdopodobnie również rozszerzę ją, aby rozszerzyć do sexp/ paragraphjeśli powtórzę ponownie).

Inicjał C-w/ M-wpobierze tylko słowo w punkcie, a wywołanie go po raz drugi przejmie całą linię.

;; *** 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
źródło
Czy to zaktualizowałeś, a jeśli tak, to gdzie jest kopia? Dodaje to również mnóstwo znaków do pierścienia znaku. Czy można dodać tylko jeden znak na początku miejsca, w którym został skopiowany? Więc początek słowa lub początek linii. Teraz dodaje za każdym razem cztery znaki, co jest denerwujące. Właściwie zmieniłem to na use (backward-sexp), ale czasami nie można go znaleźć i daje błąd. Czy może po prostu skopiować wiersz, jeśli go nie znajdzie? Nie byłem pewien, jak to zrobić, czy po prostu zignorować błąd i nie hałasować. Przepraszam, nie jestem najlepszy w lisp.
J Spen
1

Ponieważ chcesz to robić przy minimalnym naciśnięciu klawisza, możesz użyć doskonałego pakietu akordów Davida Anderssona . „Akord klawiszy” to dwa klawisze naciskane jednocześnie lub jeden klawisz naciskany dwukrotnie.

Możesz powiązać dowolne akordy klawiszowe z tymi funkcjami.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "dd"  'kill-whole-line)
(key-chord-define-global "cc"  'yank-whole-line)
ChillarAnand
źródło
Dzięki za odpowiedź :) W przeszłości kilka razy próbowałem akordów kluczowych i tak naprawdę nie mogłem się do nich przyzwyczaić. Ale to zdecydowanie przydatny dodatek do zestawu, jeśli zebrane tutaj odpowiedzi!
itsjeyd
1

Mniej doraźnym sposobem jest zdefiniowanie mark-whole-line , dla którego Emacs naprawdę powinien mieć domyślną komendę.

(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

Następnie C-2 C-w wykona robotę.

Ułatwia to także komentowanie bieżącej całej linii.

Chromatyczny
źródło
0

To jest modyfikacja odpowiedzi od itsjeyd - obecnie najwyżej głosowanej odpowiedzi, z której korzystałem od lat. Ma jednak problemy: zalecana wersja kill-ring-saveczasami zawiedzie, ponieważ znak nie jest ustawiony (zazwyczaj w nowym buforze), a nawet gdy zadziałał, kursor wykonał dziwny taniec po użyciu funkcji do skopiowania pojedynczego wiersza . Po pewnym kopaniu dotarło do mnie, że dzieje się tak, ponieważ kill-ring-savepołączenia indicate-copied-regionwykonały swoją pracę, ale ponieważ punkt i znak nie pasują do skopiowanego regionu, indicate-copied-regionoznaczono niewłaściwy region.

Wystarczająco powiedziane. Oto rozwiązanie, które temu zaradzi:

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

Nie ma nic złego w poradach itsjeyd na temat kill-region. Oto jego wariant, bardziej stylistycznie zgodny z powyższym:

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

Pamiętaj, że jeśli transient-mark-modenie jest włączony, te porady nic nie robią.

Harald Hanche-Olsen
źródło
Jeśli potrzebujesz bardziej kompleksowego rozwiązania, rozważ użycie pakietu whole-line-or-region; zobacz odpowiedź @sanityinc.
Harald Hanche-Olsen
0

Używam pakietu o nazwie composable.el . Ciekawą rzeczą w pakiecie jest to, że modyfikuje Mw i Cw (polecenia kopiowania i zabijania), aby były bardziej podobne do Vima, z tym, że akceptuje tradycyjne polecenia emacsa. Więc C-w lzabija całą linię. Ale możesz także robić rzeczy takie jak C-w M->zabijanie końca pliku. Oba polecenia działają normalnie podczas oznaczania regionu.

Greth
źródło