Created
September 30, 2023 22:55
-
-
Save rytswd/f169d5acadd8a7e688075c1bb983f915 to your computer and use it in GitHub Desktop.
Emacs: Duplicate line or region like VSCode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defun rytswd/duplicate-line-or-region-up (arg) | |
"Duplicate the current line or selected region upward." | |
(interactive "*p") | |
(dotimes (_ arg) | |
(rytswd/duplicate-line-or-region -1))) | |
(defun rytswd/duplicate-line-or-region-down (arg) | |
"Duplicate the current line or selected region downward." | |
(interactive "*p") | |
(dotimes (_ arg) | |
(rytswd/duplicate-line-or-region 1))) | |
(defun rytswd/duplicate-line-or-region (n) | |
"Duplicate the current line or selected region upward or downward. The | |
direction is determined by the argument n being positive (i.e. downward) | |
or negative (i.e. upward). When a region is in play, the region will be kept | |
in a way so that this duplicate command can be replayed multiple times." | |
(let* ((is-region (use-region-p)) | |
(beg (if is-region (region-beginning) nil)) | |
(end (if is-region (region-end) nil)) | |
(start (point)) | |
(region-other-point (if is-region (if (eq start beg) end beg))) | |
(line-start (if is-region | |
(save-mark-and-excursion | |
(goto-char beg) | |
(line-beginning-position)) | |
(line-beginning-position))) | |
(line-end (if is-region | |
(save-mark-and-excursion | |
(goto-char end) | |
(line-end-position)) | |
(line-end-position))) | |
(text (concat (buffer-substring line-start line-end) "\n")) | |
(forward (if (< 0 n) 1 -1)) | |
(shift (length text))) | |
;; If duplication direction is down (forward), keep the existing lines as | |
;; they appear, and insert before the current line. This makes it look as | |
;; if the selection has moved down, and can be used to keep duplicating | |
;; the selected lines downwards. | |
(if (> forward 0) | |
;; Because other content will be inserted, save-mark-and-excursion won't | |
;; work. For that reason, I need to do some manual mark adjustment. | |
(progn (goto-char line-start) | |
(insert text) | |
(goto-char (+ start shift)) | |
(when is-region | |
(save-excursion | |
(push-mark (+ region-other-point shift) 'nomsg nil))) | |
) | |
;; If duplication direction is up, insert the item below the current | |
;; line. This allows upward duplication to be repeated. | |
(progn (goto-char line-end) | |
(forward-line 1) | |
(insert text) | |
(goto-char start) | |
(when is-region | |
(save-excursion | |
(push-mark region-other-point 'nomsg nil))) | |
) | |
) | |
(setq deactivate-mark nil))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment