Убийте чи скопіюйте поточний рядок мінімальними натисканнями клавіш


32

Я роблю, C-a C-k C-kщоб убити всю точку прямої.

Якщо я хочу скопіювати рядок, а не вбити, я можу натиснути C-/ C-/ відразу після введення послідовності, наведеної вище.

Я також можу зробити C-a C-SPC C-n M-w.

Чи існує швидший спосіб вбити або скопіювати всю точку рядка?


1
Оце Так! Ці відповіді показують велику довжину, на яку люди будуть йти, щоб уникнути використання вбудованого kill-whole-line. :)
Омар

Як запропоновано нижче, використовуйте evil-mode. Вивчіть команди Vim, ви не пошкодуєте!
А. Завіруха

Відповіді:


44

Ви можете використовувати kill-whole-lineдля вбивства всієї точки рядка на. Положення точки не має значення. Ця команда C-S-DELза замовчуванням пов'язана.

Ви також можете доручити kill-line(зв'язаний C-k) вбити весь рядок, встановивши змінну kill-whole-line на незначущу nil:

(setq kill-whole-line t)

Зауважте, що ця точка повинна бути на початку рядка.


Потім є ці два дорогоцінні камені (через 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)))))

За допомогою цих місць ви можете вбити або скопіювати точку прямої лінії одним натисканням клавіші :

  • C-w вбиває поточну лінію
  • M-w копіює поточний рядок

Зауважте, що якщо є активний регіон, kill-regionі kill-ring-saveнадалі буде робити те, що вони зазвичай роблять: вбийте або скопіюйте його.


Перенос slick-cutі slick-copyнова система консультацій

Emacs 24.4 представляє нову систему консультацій . Поки це defadvice все ще працює , є ймовірність, що він може бути застарілим на користь нової системи в майбутніх версіях Emacs. Щоб підготуватися до цього, ви можете скористатися оновленими версіями slick-cutта 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
Зауважте, що kill-regionі kill-ring-saveдосі працює, навіть якщо регіон не "активний". Це скасує таку поведінку. Я використовую таку поведінку час від часу, але якщо ви не звикли користуватися ними таким чином, то, ймовірно, ви не помітите різниці.
nispio

@nispio Будь ласка, розкрийте, коли / як kill-regionі т. д. можна використовувати / корисно, коли mark-activeє nil.
Філ Хадсон

1
@PhilHudson Марку можна встановити (і зазвичай є) без активної роботи. Спробуйте зробити C-SPCдвічі, щоб активувати, а потім відключити марку. Перемістіть курсор в інше місце у файлі та запустіть, kill-regionі це знищить область між точкою та позначкою, навіть якщо позначка не активна. Кілька прикладів команд, які встановлюють (але не активують) позначку, є yankі isearch. Виконуючи ці команди команд, я знаю, де знаходиться позначка, навіть якщо вона не активна, і багато команд (у тому числі kill-region) дозволять мені використовувати позначку без явного її активації.
nispio

Дякую @nispio. Звичайно. Ось як це було раніше, перш ніж видиме виділення регіону стало типовою парою основних випусків назад, правда? Я плутав "активного" з "набором".
Філ Хадсон

1
Це найбільша відповідь, розміщена на будь-якому SX. Серйозно.
Бенджамін Ліндквіст

15

Я знайшов для себе рішення - використовувати аргументи префікса.

Для мене вбивство половини рядка є корисною особливістю, але я хочу і більш простий спосіб вбити цілі рядки. Тож я зробив це так, що kill-lineпросто вбиває все на виду, коли дається аргумент префікса.

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

Цей маленький макрос C-kвсе ще вбиває з точки, але C-3 C-kковтає три цілі лінії. Як бонус ми отримуємо kill-whole-lineповедінку, роблячи C-1 C-k.


Це чудова ідея, дякую, що поділилися нею! :) Як би ви адаптували це рішення для роботи над копіюванням одного чи декількох рядків? kill-ring-saveне приймає аргументи префікса ...
itsjeyd

@itsjeyd Я впевнений, що щось подібне можна зробити для об'єднання двох відповідей. Але знадобиться лише трохи більше роботи.
Малабарба

Останній рядок стосується паредити-вбивства. Це призначено?
Boccaperta-IT

1
О, добре, дякую. Я не отримую очікуваної поведінки. Якщо я розміщую вказівник на середині рядка і натискаю C-3 Ck, перший рядок не повністю знищується. Це так, як це повинно працювати, чи я роблю щось не так?
Boccaperta-IT

1
@Malabarba маєш рацію, kill-visual-lineобов'язково C-k. Я це виправлю. Знову дякую.
Boccaperta-IT

15

Існує пакет, whole-line-or-regionякий називається, який радить різні вбудовані команди, щоб вони діяли на поточний рядок, якщо жодна область не активна, тому M-wбуде скопійовано поточний рядок і C-w, наприклад, його буде вбито. Я використовую пакет протягом багатьох років, і вважаю його незамінним.

Крім того, цей пакет робить це таким чином, що числовий префікс вказуватиме кількість рядків, на які потрібно діяти, тому M-2 M-wкопіюватиме два рядки. Інші відповіді тут не забезпечують зручної функціональності.

Я взяв на себе підтримку пакета на моєму акаунті github, коли автор припинив його підтримувати і не відповідав.

whole-line-or-region також надає засоби для додавання цієї поведінки до подальших команд, якщо вам це потрібно.


Будь ласка, подайте для цього питання MELPA, тому що я не впевнений, що ви маєте на увазі: я встановлюю цей пакет від MELPA весь час без проблем.
sanityinc

9

Це не відповідь для православних емаків. Якщо, однак, ви готові хулити за допомогою evilмодального редагування, ви можете:

  • dd для лінії вбивства
  • cc для копіювання рядка

Обидва можуть бути префіксованими кількістю рядків для вбивства / копіювання (наприклад, 4ccбуде скопійовано наступні 4 рядки).


5

Окрім відповіді @itsjeyd, чи можу я запропонувати ці дві функції?

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

Потім, ключові визначення (можливо, ви захочете їх адаптувати):

(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

Надано ErgoEmacs


Дякую за вашу відповідь! Ви можете розглянути можливість її розширення, описавши, чим ці команди відрізняються від інших розміщених тут рішень. Так, ця інформація є в документах, але це не завадить зробити її більш видимою для майбутніх читачів :)
itsjeyd

1
Чи можливо це зробити, але змінити його, як @Jonathan пост нижче, щоб він спочатку взяв sexp або word, а потім приймає рядок, якщо викликається знову?
J Spen

@JSpen Те, що я роблю, - це призначити функцію ярлика. Те, що робить Джонатан, - це визначення поради щодо функції. Отже, ви можете просто порадити функцію, а потім визначити клавішу швидкого доступу до функції, що коригується; і ви отримаєте свій результат. Вибачте за затримку;)
Nsukami _

4

Як додаток до відповіді @ itsjeyd, я маю наступне. (Можливо, логіка може бути трохи очищена, і я, коли перейду на нову систему порад, я, швидше за все, також розширюю її, щоб вона поширювалася на sexp/ paragraphякщо повторюватимусь знову)

Початковий C-w/ M-wзахопить лише слово в точці, а називаючи його вдруге, захопить весь рядок.

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

Ви оновили це, і якщо так, то де це копія? Також це додає тонну марок до кільця марки. Чи можна лише додати одну позначку на початку, де вона скопійована. Отже початок слова або початок рядка. Тепер він додає як чотири позначки кожного разу, що дратує. Я фактично змінив його на використання (backward-sexp), але іноді він не може знайти його, і це дає помилку. Чи може він просто скопіювати рядок, якщо він не знайде його? Я не був впевнений, як це зробити, або просто ігнорував помилку і не шумів. Вибачте, я не найкращий на ліпі.
J Spen

1

Оскільки ви хочете зробити це з мінімальними обведеннями клавіш, ви можете використовувати відмінний пакет клавіш-акордів Девіда Андерссона . "Ключовий акорд" - це дві клавіші, натиснуті одночасно, або одна клавіша, натиснута двічі.

Ви можете прив'язати будь-які ключові акорди до цих функцій.

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

Дякую за вашу відповідь :) Я кілька разів пробував ключові акорди в минулому і не зміг до них звикнути. Але це, безумовно, корисне доповнення до набору, якщо відповіді зібрані тут!
itjeyd

1

Менш спеціальний спосіб - визначити mark-whole-line, для чого 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

Тоді C-2 C-wзробимо роботу.

Це також полегшує справи, такі як коментування поточного рядка.


0

Це модифікація відповіді itsjeyd - на даний момент відповідь, яка найбільше голосує, і якою я користувався роками. Однак у нього є проблеми: Запропонований варіант kill-ring-saveбуде колись невдалим, оскільки позначка не встановлена ​​(як правило, в новому буфері), і навіть коли вона працювала, курсор зробив дивний танець після використання функції для копіювання одного рядка . Після деякого копання мені здалося, що це відбувається тому, що kill-ring-saveдзвінки indicate-copied-regionпісля того, як вона виконала свою роботу, але як точка і позначка не відповідають скопійованій області, indicate-copied-regionпозначена неправильна область.

Достатньо сказав. Ось рішення, яке усуває це:

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

Немає нічого поганого з порадами іцдейда щодо kill-region. Ось його варіант у будь-якому випадку, стилістично більше відповідає вищесказаному:

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

Зауважте, що якщо transient-mark-modeїх не ввімкнено, ці поради нічого не роблять.


Якщо ви хочете більш комплексне рішення, whole-line-or-regionзамість цього скористайтеся пакетом ; див. відповідь від @sanityinc.
Харальд Ханш-Олсен

0

Я використовую пакет під назвою composable.el . Акуратна річ у пакеті полягає в тому, що він модифікує Mw і Cw (копіюйте та вбивайте команди), щоб бути більш схожими на Vim, оскільки поворот сприймає традиційні команди emacs. Так C-w lвбиває цілу лінію. Але ви також можете робити такі речі, як C-w M->вбити кінець файлу. Обидві команди діють як нормально під час маркування регіону.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.