Каков самый простой способ переместить выделенную область или строку (если нет выделения) вверх или вниз в emacs? Я ищу ту же функциональность, что и в eclipse (с ограничением M-up, M-down).
Я почти уверен, что идиома состоит в том, чтобы просто убить то, что вы хотите переместить, использовать обычные функции навигации (включая isearch и т. Д.), Чтобы переместить точку, в которой вы хотите, чтобы был код, а затем дергать. Помните, что есть стопка убийств, так что вам даже не нужно сразу же находить место; вы можете собрать другие кусочки, чтобы потом дергать. Лично я, как активный пользователь Emacs, не могу представить себе ситуацию, когда я бы предпочел вручную перемещать одну строку вверх или вниз. Это просто бесполезно.
jrockway
7
@jrockway: спасибо за ваш комментарий. Я думаю, что у каждого свой образ действий. Я много работаю с eclipse и очень привык перемещать линии / регионы. Одна из замечательных особенностей расширяемости emacs заключается в том, что эту функциональность можно легко добавить.
fikovnik
3
согласовано. Я часто хочу перемещать строки вверх и вниз, как вы описываете, независимо от того, работаю ли я в редакторе, который это поддерживает. Или, если на то пошло, работаю я над кодом или нет. Word поддерживает это (по абзацам) с помощью Alt + Shift + Up и Down, и я отображаю это в своих редакторах, когда могу.
harpo
6
@Drew and jrockway: Я думаю, что соглашаться на меньшее - это вряд ли способ emacs. Если вы хотите переместить линии, их просто переместить быстрее, чем kill / yankk. И, конечно же, в org-mode это реализовано по какой-то причине: действительно, есть много случаев, когда вы хотите переместить строку, перемещение неверно размещенного оператора в / из области блока является одним, изменить порядок операторов, изменить порядок документов (см. Org- mode), .. Многие люди используют его в eclipse. То, что вы не используете, вы часто не упускаете, но полезность движущихся строк является фактом для многих программистов
Питер
2
Это полезно при редактировании файлов git-rebase, содержащих списки коммитов, которые вы, возможно, захотите изменить.
Кен Уильямс
Ответы:
47
Линия может быть перемещена с помощью транспонированных линий, привязанных к C-x C-t. А вот насчет регионов не знаю.
Я нашел этот фрагмент elisp, который делает то, что вы хотите, за исключением того, что вам нужно изменить привязки.
Есть небольшая проблема как с этим решением, так и с почти идентичным решением, опубликованным @sanityinc: если я использую определенный ярлык для перемещения области вверх и / или вниз, то сразу же используйте ярлык для отмены (C-_ по умолчанию), регион просто исчезает, а сообщение «Отменить в регионе!» отображается в эхо-области. Другая команда отмены выдает сообщение «Нет дополнительной информации об отмене для региона». Однако, если я перемещаю курсор и затем выполняю команду «Отменить», отмена снова начинает работать. Относительно незначительное раздражение, но все остальные команды Emacs можно отменить немедленно, не прибегая к какой-то уловке.
Teemu Leisti
1
Это абсолютно правильный способ сделать это. Строка транспонирования по умолчанию в Emacs НЕ является правильной функцией, так как курсор перемещается на следующую строку после транспонирования, что затрудняет его пошаговое повторение.
мифический
51
Обновление: установите move-textпакет из Marmalade или MELPA, чтобы получить следующий код.
Вот что я использую, и работает как с регионами, так и с отдельными линиями:
Ах, круто, я такого раньше не видел, похоже, что в basic-edit-toolkit можно использовать очистку.
ocodo 05
1
@mcb Да, любой пакет ELPA можно установить через el-get. (Обратите внимание, что в наши дни даже автор el-get движется к package.el.) Чтобы выбрать полные строки, я бы предложил написать отдельную функцию, которая быстро выбирает текущую строку или расширяет текущую область, чтобы включить полные строки. Затем просто вызовите эту функцию перед функциями перемещения текста.
sanityinc
1
@sanityinc Спасибо за это. У меня только что был мини-Emacs 'O', когда я впервые его использовал. Хорошая вещь!
Он работает точно так же, как eclipse Alt+ Up/ Downдля отдельных линий, а также для линий выбранных регионов!
В дополнение к этому он позволяет перемещать слова с помощью Alt+ Left/ Right
Это именно то, что вы ищете! И это даже доступно в репозиториях ELPA !
Другие решения у меня никогда не работали. Некоторые из них были ошибочными (транспонирование строк при изменении их порядка, что за?), А некоторые из них перемещали точно выбранную область, оставляя невыделенные части строк на своих позициях. Но drag-stuffработает точно так же, как в eclipse!
И еще более! Вы можете попробовать выбрать регион и использовать Alt+ Left/ Right! Это переместит выбранную область на один символ влево или вправо. Удивительный!
Чтобы включить его глобально, просто запустите это:
Это действительно должно иметь необязательное перемещение влево и вправо, поскольку оно переопределяет раскладку клавиатуры emacs по умолчанию.
ocodo
@Slomojo, возможно! Почему бы вам не предложить это в emacswiki? :)
Алекс-Даниил Якименко-А.
1
Раньше этим пользовался, сейчас использую smart-shift. Мне нравится, что это DWIM для горизонтального перемещения.
jpkotta
1
Требуется (drag-stuff-define-keys)в файле инициализации до того, как комбинации клавиш начнут работать. Это объясняется в этом github: github.com/rejeep/drag-stuff.el
agent18 02 янв.2020
11
Я написал пару интерактивных функций для перемещения строк вверх / вниз:
;; move line up
(defun move-line-up ()
(interactive)
(transpose-lines1)
(previous-line2))
(global-set-key [(control shift up)] 'move-line-up)
;; move line down
(defun move-line-down ()
(interactive)
(next-line1)
(transpose-lines1)
(previous-line1))
(global-set-key [(control shift down)] 'move-line-down)
Привязки клавиш выполнены в стиле IntelliJ IDEA, но вы можете использовать все, что захотите. Возможно, мне стоит реализовать некоторые функции, которые также работают с регионами.
Вот мой фрагмент для перемещения текущей строки или строк, охватываемых активной областью. Он учитывает положение курсора и выделенную область. И он не будет разрывать линии, если область не начинается / не заканчивается на границе (ах) линии. (Он вдохновлен затмением; я нашел способ затмения более удобным, чем «транспонированные линии».)
;; move the line(s) spanned by the active region up/down (line transposing);; {{{
(defun move-lines (n)
(let ((beg) (end) (keep))
(if mark-active
(save-excursion
(setq keep t)
(setq beg (region-beginning)
end (region-end))
(goto-char beg)
(setq beg (line-beginning-position))
(goto-char end)
(setq end (line-beginning-position2)))
(setq beg (line-beginning-position)
end (line-beginning-position2)))
(let ((offset (if (and (markt)
(and (>= (markt) beg)
(< (markt) end)))
(- (point) (markt))))
(rewind (- end (point))))
(goto-char (if (< n 0) beg end))
(forward-line n)
(insert (delete-and-extract-region beg end))
(backward-char rewind)
(if offset (set-mark (- (point) offset))))
(if keep
(setq mark-active t
deactivate-mark nil))))
(defun move-lines-up (n)
"move the line(s) spanned by the active region up by N lines."
(interactive"*p")
(move-lines (- (or n 1))))
(defun move-lines-down (n)
"move the line(s) spanned by the active region down by N lines."
(interactive"*p")
(move-lines (or n 1)))
Кстати, если вы решите использовать связанный фрагмент, вы можете изменить оператор let на (let ((col (current-column)) (line-move-visual nil)), иначе вы получите забавное поведение с обернутыми строками .
Лео Alekseyev
1
transpose-paragraphФункция может помочь вам.
Вы также можете просмотреть раздел транспонирования в руководстве Emacs. По сути:
C-t
Transpose two characters (transpose-chars).
M-t
Transpose two words (transpose-words).
C-M-t
Transpose two balanced expressions (transpose-sexps).
C-x C-t
Transpose two lines (transpose-lines).
Я использую для этого пакет smart-shift (в Melpa). По умолчанию он выполняет повторную привязку C-C <arrow>к перемещению линии или области. Он перемещается по горизонтали на величину, зависящую от основного режима (например, c-basic-offset или python-indent-offset). Также работает по регионам.
Ответы:
Линия может быть перемещена с помощью транспонированных линий, привязанных к
C-x C-t
. А вот насчет регионов не знаю.Я нашел этот фрагмент elisp, который делает то, что вы хотите, за исключением того, что вам нужно изменить привязки.
(defun move-text-internal (arg) (cond ((and mark-active transient-mark-mode) (if (> (point) (mark)) (exchange-point-and-mark)) (let ((column (current-column)) (text (delete-and-extract-region (point) (mark)))) (forward-line arg) (move-to-column column t) (set-mark (point)) (insert text) (exchange-point-and-mark) (setq deactivate-mark nil))) (t (beginning-of-line) (when (or (> arg 0) (not (bobp))) (forward-line) (when (or (< arg 0) (not (eobp))) (transpose-lines arg)) (forward-line -1))))) (defun move-text-down (arg) "Move region (transient-mark-mode active) or current line arg lines down." (interactive "*p") (move-text-internal arg)) (defun move-text-up (arg) "Move region (transient-mark-mode active) or current line arg lines up." (interactive "*p") (move-text-internal (- arg))) (global-set-key [\M-\S-up] 'move-text-up) (global-set-key [\M-\S-down] 'move-text-down)
источник
Обновление: установите
move-text
пакет из Marmalade или MELPA, чтобы получить следующий код.Вот что я использую, и работает как с регионами, так и с отдельными линиями:
(defun move-text-internal (arg) (cond ((and mark-active transient-mark-mode) (if (> (point) (mark)) (exchange-point-and-mark)) (let ((column (current-column)) (text (delete-and-extract-region (point) (mark)))) (forward-line arg) (move-to-column column t) (set-mark (point)) (insert text) (exchange-point-and-mark) (setq deactivate-mark nil))) (t (let ((column (current-column))) (beginning-of-line) (when (or (> arg 0) (not (bobp))) (forward-line) (when (or (< arg 0) (not (eobp))) (transpose-lines arg) (when (and (eval-when-compile '(and (>= emacs-major-version 24) (>= emacs-minor-version 3))) (< arg 0)) (forward-line -1))) (forward-line -1)) (move-to-column column t))))) (defun move-text-down (arg) "Move region (transient-mark-mode active) or current line arg lines down." (interactive "*p") (move-text-internal arg)) (defun move-text-up (arg) "Move region (transient-mark-mode active) or current line arg lines up." (interactive "*p") (move-text-internal (- arg))) (global-set-key [M-S-up] 'move-text-up) (global-set-key [M-S-down] 'move-text-down)
источник
Тебе стоит попробовать
drag-stuff
!Он работает точно так же, как eclipse Alt+ Up/ Downдля отдельных линий, а также для линий выбранных регионов!
В дополнение к этому он позволяет перемещать слова с помощью Alt+ Left/ Right
Это именно то, что вы ищете! И это даже доступно в репозиториях ELPA !
Другие решения у меня никогда не работали. Некоторые из них были ошибочными (транспонирование строк при изменении их порядка, что за?), А некоторые из них перемещали точно выбранную область, оставляя невыделенные части строк на своих позициях. Но
drag-stuff
работает точно так же, как в eclipse!И еще более! Вы можете попробовать выбрать регион и использовать Alt+ Left/ Right! Это переместит выбранную область на один символ влево или вправо. Удивительный!
Чтобы включить его глобально, просто запустите это:
(drag-stuff-global-mode)
источник
(drag-stuff-define-keys)
в файле инициализации до того, как комбинации клавиш начнут работать. Это объясняется в этом github: github.com/rejeep/drag-stuff.elЯ написал пару интерактивных функций для перемещения строк вверх / вниз:
;; move line up (defun move-line-up () (interactive) (transpose-lines 1) (previous-line 2)) (global-set-key [(control shift up)] 'move-line-up) ;; move line down (defun move-line-down () (interactive) (next-line 1) (transpose-lines 1) (previous-line 1)) (global-set-key [(control shift down)] 'move-line-down)
Привязки клавиш выполнены в стиле IntelliJ IDEA, но вы можете использовать все, что захотите. Возможно, мне стоит реализовать некоторые функции, которые также работают с регионами.
источник
Вот мой фрагмент для перемещения текущей строки или строк, охватываемых активной областью. Он учитывает положение курсора и выделенную область. И он не будет разрывать линии, если область не начинается / не заканчивается на границе (ах) линии. (Он вдохновлен затмением; я нашел способ затмения более удобным, чем «транспонированные линии».)
;; move the line(s) spanned by the active region up/down (line transposing) ;; {{{ (defun move-lines (n) (let ((beg) (end) (keep)) (if mark-active (save-excursion (setq keep t) (setq beg (region-beginning) end (region-end)) (goto-char beg) (setq beg (line-beginning-position)) (goto-char end) (setq end (line-beginning-position 2))) (setq beg (line-beginning-position) end (line-beginning-position 2))) (let ((offset (if (and (mark t) (and (>= (mark t) beg) (< (mark t) end))) (- (point) (mark t)))) (rewind (- end (point)))) (goto-char (if (< n 0) beg end)) (forward-line n) (insert (delete-and-extract-region beg end)) (backward-char rewind) (if offset (set-mark (- (point) offset)))) (if keep (setq mark-active t deactivate-mark nil)))) (defun move-lines-up (n) "move the line(s) spanned by the active region up by N lines." (interactive "*p") (move-lines (- (or n 1)))) (defun move-lines-down (n) "move the line(s) spanned by the active region down by N lines." (interactive "*p") (move-lines (or n 1)))
источник
В вики-странице emacs есть запись только для этого:
http://www.emacswiki.org/emacs/MoveLine
Для движущихся регионов:
http://www.emacswiki.org/emacs/MoveRegion
источник
Встроенного нет. Вы можете использовать транспонированные линии (Cx Ct), но вы не можете использовать его повторно. Посмотрите функции на http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/ .
Это должно быть легко адаптировать к регионам.
источник
transpose-paragraph
Функция может помочь вам.Вы также можете просмотреть раздел транспонирования в руководстве Emacs. По сути:
C-t Transpose two characters (transpose-chars). M-t Transpose two words (transpose-words). C-M-t Transpose two balanced expressions (transpose-sexps). C-x C-t Transpose two lines (transpose-lines).
источник
Я использую для этого пакет smart-shift (в Melpa). По умолчанию он выполняет повторную привязку
C-C <arrow>
к перемещению линии или области. Он перемещается по горизонтали на величину, зависящую от основного режима (например, c-basic-offset или python-indent-offset). Также работает по регионам.;; binds C-C <arrows> (when (require 'smart-shift nil 'noerror) (global-smart-shift-mode 1))
источник