Как мне продублировать целую строку в Emacs?


155

Я видел этот же вопрос для VIM, и я сам хотел узнать, как это сделать для Emacs. В ReSharper я использую CTRL-D для этого действия. Какое наименьшее количество команд для выполнения этого в Emacs?


2
Конечно, это emacs, так что TMTOWTDI - их 22! (и считает) c2.com/cgi/wiki?ThereIsMoreThanOneWayToDoIt
Том

Ответы:


150

я использую

C-a C-SPACE C-n M-w C-y

который разбивается на

  • C-a: переместить курсор в начало строки
  • C-SPACE: начать выбор («установить отметку»)
  • C-n: переместить курсор на следующую строку
  • M-w: копия региона
  • C-y: paste ("янки")

Вышеупомянутое

C-a C-k C-k C-y C-y

составляет одно и то же (TMTOWTDI)

  • C-a: переместить курсор в начало строки
  • C-k: cut ("kill") строка
  • C-k: вырезать новую строку
  • C-y: paste ("yank") (мы вернулись на круги своя)
  • C-y: вставьте снова (теперь у нас есть две копии строки)

Они оба смущающе многословны по сравнению с C-dвашим редактором, но в Emacs всегда есть настройка. по умолчанию C-dсвязано delete-char, так как насчет C-c C-d? Просто добавьте следующее к себе .emacs:

(global-set-key "\C-c\C-d" "\C-a\C- \C-n\M-w\C-y")

(Версия elisp @ Nathan, вероятно, предпочтительнее, потому что она не сломается, если будет изменена какая-либо из привязок клавиш.)

Осторожно: некоторые режимы Emacs могут восстанавливаться, C-c C-dчтобы делать что-то еще.


5
Здравствуй! Имейте в виду, что если у вас есть '(setq kill-whole-line t)', вам понадобится только один 'Ck' (решение 2), поскольку он уже убивает символ новой строки вместе с содержимым строки. Мое предпочтительное использование 'C-k'. Ура, Даниэль
Даниэльпое

179
Это действительно смущает.
тофутим

18
Как насчет C-S-backspace C-y C-y?
Ericzma

1
что такое Mw? какой ключ использовать для этого?
Бала

4
@Bala "M" - это "Meta" (обычно это Esc или Alt, это зависит от вашей раскладки клавиатуры). «Mw» означает «Meta» и «w» одновременно (на моей клавиатуре «Alt-w»).
Крис Конвей

96

В дополнение к предыдущим ответам вы также можете определить свою собственную функцию для дублирования строки. Например, добавив следующее в ваш файл .emacs, вы заставите Cd дублировать текущую строку.

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (open-line 1)
  (next-line 1)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)

Я получаю следующую ошибку с этим:Symbol's function definition is void: move-beginning-of-line
Rohaq

5
Проблема в том, что клавиша «Del» также привязана к дублированию строки ...
Дэвид Гомес

Итак, есть ли идеи о том, как отвязать Delот этой функции?
Александр Щебликин

Хорошо, найдено решение возврата Delк нормальному состоянию с сохранением нового C-d: (global-set-key (kbd "<delete>") 'delete-char)необходимо добавить после C-dопределения.
Александр Щебликин

Попытка сделать это на пустой строке приводит к вставке двух строк вместо одной. Я не знаю почему. Есть ли легкое исправление?
Зельфир Кальцталь

68

Поместите курсор на строку, если не в начале, сделайте CTRL- A, тогда:

CTRL-K

CTRL-K

CTRL-Y

CTRL-Y


Я не думаю, что второй CY необходим.
Бастьен Леонар

4
без него не будет дубликата
епатель

17
Используйте CS-Backspace (kill-whole-line) вместо Ck. Вам не нужно винт с позицией курсора или убийство новой строки.
Ницше Джоу

Это хорошо работает, но нет ли короткого пути сделать это?
Страйкер

52

Моя версия функции для дублирования строки, которая хорошо работает с отменой и не портит позицию курсора. Это было результатом обсуждения в gnu.emacs.sources с ноября 1997 года .

(defun duplicate-line (arg)
  "Duplicate current line, leaving point in lower line."
  (interactive "*p")

  ;; save the point for undo
  (setq buffer-undo-list (cons (point) buffer-undo-list))

  ;; local variables for start and end of line
  (let ((bol (save-excursion (beginning-of-line) (point)))
        eol)
    (save-excursion

      ;; don't use forward-line for this, because you would have
      ;; to check whether you are at the end of the buffer
      (end-of-line)
      (setq eol (point))

      ;; store the line and disable the recording of undo information
      (let ((line (buffer-substring bol eol))
            (buffer-undo-list t)
            (count arg))
        ;; insert the line arg times
        (while (> count 0)
          (newline)         ;; because there is no newline in 'line'
          (insert line)
          (setq count (1- count)))
        )

      ;; create the undo information
      (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))
    ) ; end-of-let

  ;; put the point in the lowest line and return
  (next-line arg))

Затем вы можете определить CTRL-D для вызова этой функции:

(global-set-key (kbd "C-d") 'duplicate-line)

Превосходно! Функция отмены и позиционирования курсора делает его лучшим. Спасибо!
PTRN

также по ссылке есть код для регионов!
pcarvalho

Очень хорошее решение. Thx
Plankalkül

Прекрасно работает. Спасибо за решение.
Страйкер

@pesche crux-duplicate-current-line-or-regionработает лучше для меня, потому что с вашей функцией он отменяет дублирование строк и последнюю операцию.
rofrol

47

Вместо kill-line( C-k) C-a C-k C-k C-y C-y используется kill-whole-lineкоманда:

C-S-Backspace
C-y
C-y

Преимущества перед этим C-kвключают в себя то, что не имеет значения, где находится точка на линии (в отличие от C-kкоторой требуется находиться в начале линии), а также убивает символ новой строки (опять же, что-то C-kне так).


2
Слава @RayVega! Я попробовал это решение, и оно работает как чемпион (в любом случае, в моем GNU Emacs 23.3.1). Разве это решение не работает для некоторых людей? Это лучший ответ на ваш (собственный) вопрос.
JS.

1
Вы должны принять этот ответ как правильный. Он делает именно то, что вы просили, и в «наименьшем количестве команд».
Davor Cubranic

24

Вот еще одна функция для этого. Моя версия не касается кольца уничтожения, и курсор оказывается на новой строке, где он был на оригинале. Он будет дублировать регион, если он активен (режим переходной метки), или по умолчанию дублирует строку в противном случае. Он также сделает несколько копий, если ему присваивается префиксный аргумент, и закомментирует исходную строку, если ему присваивается отрицательный префиксный аргумент (это полезно для тестирования другой версии команды / оператора при сохранении старой).

(defun duplicate-line-or-region (&optional n)
  "Duplicate current line, or region if active.
With argument N, make N copies.
With negative N, comment out original line and use the absolute value."
  (interactive "*p")
  (let ((use-region (use-region-p)))
    (save-excursion
      (let ((text (if use-region        ;Get region if active, otherwise line
                      (buffer-substring (region-beginning) (region-end))
                    (prog1 (thing-at-point 'line)
                      (end-of-line)
                      (if (< 0 (forward-line 1)) ;Go to beginning of next line, or make a new one
                          (newline))))))
        (dotimes (i (abs (or n 1)))     ;Insert N times, or once if not specified
          (insert text))))
    (if use-region nil                  ;Only if we're working with a line (not a region)
      (let ((pos (- (point) (line-beginning-position)))) ;Save column
        (if (> 0 n)                             ;Comment out original with negative arg
            (comment-region (line-beginning-position) (line-end-position)))
        (forward-line 1)
        (forward-char pos)))))

Я связан с C-c d:

(global-set-key [?\C-c ?d] 'duplicate-line-or-region)

Это никогда не должно быть переназначено режимом или чем-то еще, потому что C-cпосле одной (неизмененной) буквы зарезервировано для привязок пользователя.


Лучшее решение на данный момент
Лев Уфимцев

1
Я помещаю это в мой файл .emacs, но когда я пытаюсь использовать, C-c dя получаю ошибку command-execute: Wrong type argument: commandp, duplicate-line-or-region. Есть идеи, что случилось? Я использую Emacs 25.1.1 на Windows
junius

Действительно хорошее решение, я ценю функцию региона и функцию комментирования с отрицательным аргументом. Также как предложенная привязка ключа.
Алекс Трумэн

18

Добавление Натана в ваш файл .emacs - это путь, но его можно немного упростить, заменив

  (open-line 1)
  (next-line 1)

с участием

  (newline)

получая

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (newline)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)

Это хорошо. Спасибо!
Техасбубане


5

Я не совсем помню, как дублирование строк работает где-то еще, но как бывший пользователь SciTE мне понравилась одна вещь в SciTE-way: она не касается позиции курсора! Так что все перечисленные выше отзывы не были достаточно хороши для меня, вот моя хиппи-версия:

(defun duplicate-line ()
    "Clone line at cursor, leaving the latter intact."
    (interactive)
    (save-excursion
        (let ((kill-read-only-ok t) deactivate-mark)
            (toggle-read-only 1)
            (kill-whole-line)
            (toggle-read-only 0)
            (yank))))

Обратите внимание, что на самом деле ничто не убивается в процессе, оставляя метки и текущий выбор без изменений.

Кстати, почему вы, ребята, так любите дергать курсором, когда есть эта приятная и чистая вещь, убивающая всю линию (CS-backspace)?



4

то, что вы можете захотеть иметь в вашем .emacs

(setq kill-whole-line t)

Который в основном убивает всю строку плюс новую строку всякий раз, когда вы вызываете kill-line (т.е. через Ck). Тогда без лишнего кода, вы можете просто сделать Ca Ck Cy Cy, чтобы продублировать строку. Это ломается к

C-a go to beginning of line
C-k kill-line (i.e. cut the line into clipboard)
C-y yank (i.e. paste); the first time you get the killed line back; 
    second time gives the duplicated line.

Но если вы используете это часто, то, возможно, лучше было бы использовать выделенную привязку ключа, но преимущество простого использования Ca Ck Cy Cy заключается в том, что вы можете дублировать строку в другом месте, а не чуть ниже текущей строки.


4

Я copy-from-above-commandсвязался с ключом и использую это. Он поставляется с XEmacs, но я не знаю о GNU Emacs.

`copy-from-over-command '- это интерактивная скомпилированная функция Lisp,
загружаемая из" /usr/share/xemacs/21.4.15/lisp/misc.elc "(команда copy-from-вышеуказанная-команда & необязательный ARG)

Документация: Скопируйте символы из предыдущей непустой строки , начиная чуть выше точки. Скопируйте символы ARG, но не после конца этой строки. Если аргумент не указан, скопируйте всю оставшуюся часть строки. Скопированные символы вставляются в буфер перед точкой.


Что касается версии 23, она также является частью стандартного дистрибутива GNU Emacs.
viam0Zah

Это не похоже на мою версию. Что-то должно быть загружено? Моя версия GNU Emacs 23.2.1 (amd64-portbld-freebsd8.1) of 2010-11-14 on [host clipped].
Qmega

2
@qmega Вы должны сделать (требуют разное).
Дмитрий

4

Существует пакет под названием Avy. Он имеет команду avy-copy-line. Когда вы используете эту команду, каждая строка в вашем окне получает комбинацию букв. Тогда вам просто нужно набрать комбинацию, и вы получите эту строку. Это также работает для региона. Тогда вам просто нужно набрать две комбинации.

Здесь вы можете увидеть интерфейс:

введите описание изображения здесь



3

Значения по умолчанию ужасны для этого. Однако вы можете расширить Emacs, чтобы он работал как SlickEdit и TextMate, то есть копировать / вырезать текущую строку, когда текст не выделен:

(transient-mark-mode t)
(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)))))
(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)))))

Поместите выше в .emacs. Затем скопировать строку M-w. Чтобы удалить строку, C-w. Для дублирования строки C-a M-w C-y C-y C-y ....


3

«Я написал свою собственную версию duplicate-line, потому что я не хочу облажаться с убийственным кольцом.

  (defun jr-duplicate-line ()
    "EASY"
    (interactive)
    (save-excursion
      (let ((line-text (buffer-substring-no-properties
                        (line-beginning-position)
                        (line-end-position))))
        (move-end-of-line 1)
        (newline)
        (insert line-text))))
  (global-set-key "\C-cd" 'jr-duplicate-line)

3

Мне понравилась версия FraGGod, за исключением двух вещей: (1) Она не проверяет, доступен ли буфер только для чтения с (interactive "*") , и (2) он терпит неудачу в последней строке буфера, если последняя строка пуста (как вы не может убить строку в этом случае), оставляя ваш буфер только для чтения.

Я внес следующие изменения, чтобы решить эту проблему:

(defun duplicate-line ()
  "Clone line at cursor, leaving the latter intact."
  (interactive "*")
  (save-excursion
    ;; The last line of the buffer cannot be killed
    ;; if it is empty. Instead, simply add a new line.
    (if (and (eobp) (bolp))
        (newline)
      ;; Otherwise kill the whole line, and yank it back.
      (let ((kill-read-only-ok t)
            deactivate-mark)
        (toggle-read-only 1)
        (kill-whole-line)
        (toggle-read-only 0)
        (yank)))))

3

В последних версиях Emacs вы можете использовать Mw в любом месте строки, чтобы скопировать его. Так и становится:

M-w C-a RET C-y

В самом деле? Каким "недавним" Emacs это будет? Не в случае с 24.4: вы получаете «Метка не установлена, значит, нет региона».
Davor Cubranic

текущий Emacs 24,5, и M-wсвязан с easy-kill. Проверьте, что вы получаете, когда делаетеC-h c M-w
Луи Коттманн

Не работал в Emacs 24.5.1. Копируется только с начала строки до точки в начале той же строки после вставки предыдущей пустой строки.
Дерек Махар

3

Во всяком случае, я видел очень сложные решения ...

(defun duplicate-line ()
  "Duplicate current line"
  (interactive)
  (kill-whole-line)
  (yank)
  (yank))
(global-set-key (kbd "C-x M-d") 'duplicate-line)

Обратите внимание, что это запутается с kill ring.
Доджи

Это добавляет строку к себе, когда это последняя строка, и файл не заканчивается новой строкой
Марк

2

@ [Кевин Коннер]: Насколько я знаю, довольно близко. Единственное, что нужно учитывать, это kill-whole-lineвключить новую строку в Ck.


@Allen: удалить [и ]в@[Kevin Conner]
JFS

2

ctrl- k, ctrl- k, (позиция в новом месте)ctrl -y

Добавьте ctrl- aесли вы не начинаете с начала строки. А 2-й ctrl- kэто захватить символ новой строки. Его можно удалить, если вы просто хотите текст.


Это должен быть самый простой метод здесь. Спасибо!
bartlomiej.n

2

При интерактивном вызове без активной области, COPY (Mw) вместо одной строки:

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

При интерактивном вызове без активной области KILL (Cw) вместо одной строки.

(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))
     (message "Killed line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

Кроме того, на связанной ноте:

(defun move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode))

(defun move-line-down ()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode))

(global-set-key [(meta shift up)]  'move-line-up)
(global-set-key [(meta shift down)]  'move-line-down)

1

Я пишу один для моего предпочтения.

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
        (cur-col (current-column)))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)

Но я обнаружил, что это будет иметь некоторые проблемы, когда текущая строка содержит многобайтовые символы (например, символы CJK). Если вы столкнулись с этой проблемой, попробуйте это:

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let* ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
         (cur-col (length (buffer-substring-no-properties (point-at-bol) (point)))))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)

1

Эта функциональность должна соответствовать реализации JetBrains с точки зрения дублирования как по линии, так и по региону, а затем покидания точки и / или активной области, как ожидается:

Просто обертка вокруг интерактивной формы:

(defun wrx/duplicate-line-or-region (beg end)
  "Implements functionality of JetBrains' `Command-d' shortcut for `duplicate-line'.
   BEG & END correspond point & mark, smaller first
   `use-region-p' explained: 
   http://emacs.stackexchange.com/questions/12334/elisp-for-applying-command-to-only-the-selected-region#answer-12335"
  (interactive "r")
  (if (use-region-p)
      (wrx/duplicate-region-in-buffer beg end)
    (wrx/duplicate-line-in-buffer)))

Который называет это,

(defun wrx/duplicate-region-in-buffer (beg end)
  "copy and duplicate context of current active region
   |------------------------+----------------------------|
   |        before          |           after            |
   |------------------------+----------------------------|
   | first <MARK>line here  | first line here            |
   | second item<POINT> now | second item<MARK>line here |
   |                        | second item<POINT> now     |
   |------------------------+----------------------------|
   TODO: Acts funky when point < mark"
  (set-mark-command nil)
  (insert (buffer-substring beg end))
  (setq deactivate-mark nil))

Или это

(defun wrx/duplicate-line-in-buffer ()
  "Duplicate current line, maintaining column position.
   |--------------------------+--------------------------|
   |          before          |          after           |
   |--------------------------+--------------------------|
   | lorem ipsum<POINT> dolor | lorem ipsum dolor        |
   |                          | lorem ipsum<POINT> dolor |
   |--------------------------+--------------------------|
   TODO: Save history for `Cmd-Z'
   Context: 
   http://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs#answer-551053"
  (setq columns-over (current-column))
  (save-excursion
    (kill-whole-line)
    (yank)
    (yank))
  (let (v)
    (dotimes (n columns-over v)
      (right-char)
      (setq v (cons n v))))
  (next-line))

И тогда у меня есть это связано с мета + Shift + D

(global-set-key (kbd "M-D") 'wrx/duplicate-line-or-region)

1

Как упоминалось в других ответах, связывание нажатий клавиш с кодом lisp - это лучшая идея, чем связывание их с другими нажатиями клавиш. С ответом @ mw код дублирует строку и перемещает метку в конец новой строки. Эта модификация сохраняет положение метки в том же столбце на новой строке:

fun duplicate-line ()
  (interactive)
  (let ((col (current-column)))
    (move-beginning-of-line 1)
    (kill-line)
    (yank)
    (newline)
    (yank)
    (move-to-column col)))

1

Если вы используете Spacemacs, вы можете просто использовать duplicate-line-or-region, привязанный к:

SPC x l d 

0

С префиксными аргументами и интуитивным поведением (я надеюсь):

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (next-line 
   (save-excursion 
     (let ((beg (line-beginning-position))
           (end (line-end-position)))
       (copy-region-as-kill beg end)
       (dotimes (num arg arg)
         (end-of-line) (newline)
         (yank))))))

Курсор останется на последней строке. Кроме того, вы можете указать префикс для дублирования следующих нескольких строк:

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (save-excursion 
    (let ((beg (line-beginning-position))
          (end 
           (progn (forward-line (1- arg)) (line-end-position))))
      (copy-region-as-kill beg end)
      (end-of-line) (newline)
      (yank)))
  (next-line arg))

Я часто использую оба, используя функцию-обертку, чтобы переключать поведение аргумента префикса.

И связывание клавиш: (global-set-key (kbd "C-S-d") 'duplicate-line)


0
;; http://www.emacswiki.org/emacs/WholeLineOrRegion#toc2
;; cut, copy, yank
(defadvice kill-ring-save (around slick-copy activate)
  "When called interactively with no active region, copy a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (buffer-substring (line-beginning-position)
                                (line-beginning-position 2))
              nil '(yank-line))
    (message "Copied line")))
(defadvice kill-region (around slick-copy activate)
  "When called interactively with no active region, kill a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (filter-buffer-substring (line-beginning-position)
                                       (line-beginning-position 2) t)
              nil '(yank-line))))
(defun yank-line (string)
  "Insert STRING above the current line."
  (beginning-of-line)
  (unless (= (elt string (1- (length string))) ?\n)
    (save-excursion (insert "\n")))
  (insert string))

(global-set-key (kbd "<f2>") 'kill-region)    ; cut.
(global-set-key (kbd "<f3>") 'kill-ring-save) ; copy.
(global-set-key (kbd "<f4>") 'yank)           ; paste.

добавьте вышеупомянутый elisp к вам init.el, и вы получите функцию вырезания / копирования всей строки, затем вы можете F3 F4 дублировать строку.


0

Самый простой способ - это метод Криса Конвея.

C-a C-SPACE C-n M-w C-y

Это способ по умолчанию, предписанный EMACS. На мой взгляд, лучше использовать стандарт. Я всегда осторожен в настройке собственной привязки ключей в EMACS. EMACS уже достаточно мощный, я думаю, что мы должны стараться изо всех сил адаптироваться к его собственным привязкам клавиш.

Хотя это немного длинно, но когда вы к этому привыкли, вы можете делать быстро и найдете, что это весело!


4
Учитывая все обстоятельства, Emacs требует очень мало - огромная победа, которую он дает вам, заключается в простоте настройки его под ваши собственные нужды. Конечно , в практике есть много стандартных способов делать вещи , которые это выгодно придерживаться, но если вы используете « по умолчанию» Emacs и делать что - то более трудный путь , чем это необходимо только потому , что вы думаете « что лучше использовать стандарт» , вы в значительной степени делаете это неправильно.
Филс

0

Вот функция для дублирования текущей строки. С префиксными аргументами, он будет дублировать строку несколько раз. Например, C-3 C-S-oдублирует текущую строку три раза. Не меняет кольцо убийства.

(defun duplicate-lines (arg)
  (interactive "P")
  (let* ((arg (if arg arg 1))
         (beg (save-excursion (beginning-of-line) (point)))
         (end (save-excursion (end-of-line) (point)))
         (line (buffer-substring-no-properties beg end)))
    (save-excursion
      (end-of-line)
      (open-line arg)
      (setq num 0)
      (while (< num arg)
        (setq num (1+ num))
        (forward-line 1)
        (insert-string line))
      )))

(global-set-key (kbd "C-S-o") 'duplicate-lines)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.