Bunuh atau salin baris saat ini dengan penekanan tombol minimal

32

Saya lakukan C-a C-k C-kuntuk membunuh seluruh titik garis aktif.

Jika saya ingin menyalin garis alih-alih membunuhnya, saya dapat menekan C-/ C-/ tepat setelah mengetik urutan di atas.

Atau, saya bisa melakukannya C-a C-SPC C-n M-w.

Apakah ada cara yang lebih cepat untuk membunuh atau menyalin seluruh titik garis aktif?

itu hanya
sumber
1
Wow! Jawaban ini menunjukkan seberapa besar orang akan pergi untuk menghindari penggunaan built-in kill-whole-line. :)
Omar
Seperti yang disarankan di bawah ini, gunakan evil-mode. Pelajari perintah Vim, Anda tidak akan menyesal!
A. Blizzard

Jawaban:

44

Anda dapat menggunakan kill-whole-lineuntuk membunuh seluruh titik garis aktif. Posisi titik tidak masalah. Perintah ini terikat C-S-DELsecara default.

Anda juga dapat menginstruksikan kill-line(terikat pada C-k) untuk membunuh seluruh baris dengan mengatur variabel kill-whole-line ke nilnilai yang tidak bernilai:

(setq kill-whole-line t)

Perhatikan bahwa titik tersebut harus berada di awal baris agar ini berfungsi.


Lalu ada dua permata ini (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)))))

Dengan ini di tempat Anda dapat membunuh atau menyalin titik garis aktif dengan satu penekanan tombol :

  • C-w membunuh baris saat ini
  • M-w menyalin baris saat ini

Perhatikan bahwa jika ada wilayah aktif, kill-regiondan kill-ring-saveakan terus melakukan apa yang biasanya mereka lakukan: Bunuh atau salin.


Porting slick-cutdan slick-copyke sistem saran baru

Emacs 24.4 memperkenalkan sistem saran baru . Sementara defadvice masih berfungsi , ada kemungkinan bahwa itu akan ditinggalkan demi sistem baru dalam versi Emacs di masa depan. Untuk mempersiapkan itu, Anda mungkin ingin menggunakan versi terbaru dari slick-cutdan 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)
itu hanya
sumber
2
Catat itu kill-regiondan kill-ring-savemasih berfungsi bahkan ketika wilayah itu tidak "aktif." Ini akan mengesampingkan perilaku itu. Saya menggunakan perilaku itu dari waktu ke waktu, tetapi jika Anda tidak terbiasa menggunakannya dengan cara ini, maka Anda mungkin tidak akan melihat perbedaannya.
nispio
@nispio Silakan memperluas kapan / bagaimana kill-regionetc dapat digunakan / berguna ketika mark-activeadalah nil.
Phil Hudson
1
@ PhilHudson Tanda itu dapat (dan biasanya) diset tanpa aktif. Coba lakukan C-SPCdua kali untuk mengaktifkan dan kemudian menonaktifkan tanda. Pindahkan kursor di tempat lain dalam file dan jalankan kill-regiondan itu akan membunuh wilayah antara titik dan tanda, meskipun tanda itu tidak aktif. Beberapa contoh perintah yang mengatur (tetapi tidak mengaktifkan) tanda adalah yankdan isearch. Setelah melakukan perintah semacam ini, saya tahu di mana tandanya, bahkan jika itu tidak aktif, dan banyak perintah (termasuk kill-region) akan membiarkan saya menggunakan tandanya tanpa secara eksplisit mengaktifkannya.
nispio
Terima kasih @nispio. Tentu saja. Begitulah dulu, secara eksklusif, sebelum menyoroti wilayah yang terlihat menjadi default beberapa rilis utama kembali, kan? Saya bingung "aktif" dengan "set".
Phil Hudson
1
Ini adalah jawaban terbesar yang pernah diposting di SX apa pun. Serius.
Benjamin Lindqvist
15

Solusi yang saya temukan untuk diri saya sendiri adalah dengan menggunakan argumen awalan.

Bagi saya, membunuh setengah baris adalah fitur yang berguna, tetapi saya ingin cara yang lebih mudah untuk membunuh seluruh baris juga. Jadi saya membuatnya sehingga kill-linehanya membunuh semua yang terlihat ketika diberi argumen awalan.

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

Dengan makro kecil ini, C-kmasih membunuh dari titik, tetapi C-3 C-kmenelan tiga baris penuh. Sebagai bonus, kita mendapatkan kill-whole-lineperilaku dengan melakukan C-1 C-k.

Malabarba
sumber
Itu ide yang bagus, terima kasih sudah berbagi! :) Bagaimana Anda mengadaptasi solusi ini agar berfungsi untuk menyalin satu atau lebih baris? kill-ring-savetidak menerima argumen awalan ...
itsjeyd
@itsjeyd Saya yakin sesuatu yang serupa dapat dilakukan untuk menggabungkan dua jawaban. Tapi itu akan membutuhkan sedikit lebih banyak pekerjaan.
Malabarba
Baris terakhir mengacu pada paredit-kill. Apakah ini dimaksudkan?
Boccaperta-IT
1
Oh, baiklah, terima kasih. Saya tidak mendapatkan perilaku yang diharapkan. Jika saya menempatkan pointer di tengah garis dan menekan C-3 Ck, baris pertama tidak sepenuhnya terbunuh. Apakah ini seharusnya berfungsi atau saya melakukan sesuatu yang salah?
Boccaperta-IT
1
@Malabarba kamu benar, kill-visual-linepasti C-k. Saya akan memperbaikinya. Terima kasih lagi.
Boccaperta-IT
15

Ada paket bernama whole-line-or-regionyang menyarankan berbagai perintah bawaan sehingga mereka bertindak pada baris saat ini jika tidak ada wilayah yang aktif, sehingga M-wakan menyalin baris saat ini, dan C-wakan membunuhnya, misalnya. Saya telah menggunakan paket ini selama bertahun-tahun, dan merasa sangat diperlukan.

Selain itu, paket ini membuatnya sehingga awalan numerik akan menunjukkan jumlah baris yang akan ditindaklanjuti, sehingga M-2 M-wakan menyalin dua baris. Jawaban lain di sini tidak menyediakan fungsionalitas praktis itu.

Saya mengambil alih pemeliharaan paket di akun github saya ketika penulis berhenti memeliharanya dan menjadi tidak responsif.

whole-line-or-region juga menyediakan fasilitas untuk menambahkan perilaku ini ke perintah lebih lanjut, jika Anda membutuhkannya.

sanityinc
sumber
Harap ajukan masalah MELPA untuk itu, karena saya tidak yakin apa yang Anda maksud: Saya menginstal paket ini dari MELPA sepanjang waktu tanpa masalah.
sanityinc
9

Ini bukan jawaban untuk emacs ortodoks. Namun, jika Anda bersedia menghujat dengan evilpengeditan modal, Anda dapat:

  • dd untuk garis pembunuhan
  • cc untuk garis salinan

Keduanya dapat diawali dengan jumlah baris untuk membunuh / menyalin (misalnya, 4ccakan menyalin 4 baris berikutnya).

Dan
sumber
5

Selain jawaban @itsjeyd, bolehkah saya menyarankan kedua fungsi itu?

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

Kemudian, definisi kunci (Anda mungkin ingin mengadaptasinya):

(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

Atas perkenan ErgoEmacs

Nsukami _
sumber
Terima kasih atas jawaban anda! Anda mungkin ingin mempertimbangkan untuk memperpanjang sedikit dengan menjelaskan bagaimana perintah ini berbeda dari solusi lain yang diposting di sini. Ya, informasi ini tersedia dalam dokumen, tetapi tidak ada salahnya untuk membuatnya lebih terlihat bagi pembaca masa depan :)
itsjeyd
1
Apakah mungkin untuk melakukan ini tetapi memodifikasinya seperti @Jonathan memposting di bawah ini sehingga terlebih dahulu mengambil sexp atau kata dan kemudian mengambil baris jika dipanggil lagi?
J Spen
@JSpen Yang saya lakukan adalah menetapkan tombol pintas untuk berfungsi. Apa yang dilakukan Jonathan adalah mendefinisikan saran untuk suatu fungsi. Jadi, Anda bisa memberi saran fungsi, lalu menentukan kunci pintas ke fungsi yang disarankan; dan Anda akan mendapatkan hasilnya. Maaf atas keterlambatan;)
Nsukami _
4

Sebagai perpanjangan dari jawaban @ itsjeyd di atas, saya memiliki yang berikut. (Logikanya mungkin bisa dibersihkan sedikit dan saya akan ketika saya port ke sistem saran baru, saya mungkin juga akan memperpanjang untuk memperpanjang ke sexp/ paragraphjika diulang lagi).

Inisial C-w/ M-whanya akan mengambil kata pada titik, sementara memanggilnya kedua kalinya akan mengambil seluruh baris.

;; *** 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
sumber
Apakah Anda memperbarui ini dan jika demikian di mana salinannya? Juga, ini menambahkan satu ton tanda ke cincin tanda. Bisakah itu hanya menambahkan satu tanda di awal tempat itu disalin. Jadi awal kata atau awal baris. Sekarang ia menambahkan empat tanda setiap kali yang menjengkelkan. Saya sebenarnya telah mengubahnya untuk menggunakan (backward-sexp) tetapi kadang-kadang tidak dapat menemukannya dan memberikan kesalahan. Bisakah itu hanya menyalin garis jika tidak menemukannya? Saya tidak yakin bagaimana melakukan ini atau hanya mengabaikan kesalahan dan tidak membuat suara. Maaf, saya bukan yang terbaik di lisp.
J Spen
1

Karena Anda ingin melakukannya dengan penekanan tombol minimal, Anda dapat menggunakan paket kunci-kunci David Andersson yang sangat baik . "Kunci nada" adalah dua tombol yang ditekan secara bersamaan, atau satu tombol yang ditekan dua kali.

Anda dapat mengikat akord kunci apa saja ke fungsi-fungsi itu.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "dd"  'kill-whole-line)
(key-chord-define-global "cc"  'yank-whole-line)
ChillarAnand
sumber
Terima kasih atas jawaban Anda :) Saya mencoba kunci-kunci kunci beberapa kali di masa lalu dan tidak bisa benar-benar terbiasa dengannya. Tapi ini jelas merupakan tambahan yang berguna untuk set jika jawaban dikumpulkan di sini!
itsjeyd
1

Cara yang kurang ad-hoc adalah mendefinisikan mark-whole-line, yang mana Emacs harus memiliki perintah default untuknya.

(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

Maka C-2 C-wakan melakukan pekerjaan.

Itu juga membuat segalanya lebih mudah seperti mengomentari seluruh baris saat ini.

Berwarna
sumber
0

Ini adalah modifikasi dari jawaban oleh itsjeyd - saat ini jawaban dengan suara terbanyak, dan yang telah saya gunakan selama bertahun-tahun. Namun, ia memiliki masalah: Versi disarankan kill-ring-savekadang-kadang akan gagal karena tanda tidak disetel (biasanya di buffer baru), dan bahkan ketika itu berhasil, kursor melakukan tarian aneh setelah menggunakan fungsi untuk menyalin satu baris . Setelah beberapa penggalian, saya sadar bahwa ini terjadi karena kill-ring-savepanggilan indicate-copied-regionsetelah melakukan tugasnya, tetapi sebagai titik dan tanda tidak cocok dengan wilayah yang disalin, indicate-copied-regionditandai wilayah yang salah.

Cukup kata. Berikut adalah solusi yang memperbaiki ini:

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

Tidak ada yang salah dengan saran mereka kill-region. Berikut ini adalah varian dari semuanya, secara gaya lebih konsisten dengan yang di atas:

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

Perhatikan bahwa jika transient-mark-modetidak dinyalakan, saran ini tidak melakukan apa pun.

Harald Hanche-Olsen
sumber
Jika Anda menginginkan solusi yang lebih komprehensif, pertimbangkan untuk menggunakan paket whole-line-or-regionsebagai gantinya; lihat jawabannya oleh @sanityinc.
Harald Hanche-Olsen
0

Saya menggunakan paket yang disebut composable.el . Hal yang rapi tentang paket ini adalah memodifikasi Mw dan Cw (menyalin dan membunuh perintah) menjadi lebih seperti Vim dengan twist karena menerima perintah emacs tradisional sebagai gantinya. Jadi, C-w lbunuh seluruh lini. Tetapi Anda juga dapat melakukan hal-hal seperti C-w M->membunuh file. Kedua perintah bertindak seperti biasa ketika menandai suatu wilayah.

Greth
sumber