From 1b64ed6d6a6eb488d38ace1b55bc49646613909d Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Thu, 29 Jun 2023 10:13:09 +0300 Subject: [PATCH] * lisp/misc.el (duplicate-line-final-position): New defcustom (bug#64185). * lisp/misc.el (duplicate-line): Use it. * test/lisp/misc-tests.el (misc--duplicate-line): Add tests for duplicate-line-final-position. --- etc/NEWS.29 | 4 +++- lisp/misc.el | 33 +++++++++++++++++++++++++++------ test/lisp/misc-tests.el | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/etc/NEWS.29 b/etc/NEWS.29 index ca0d602e9ad..aa3b758a815 100644 --- a/etc/NEWS.29 +++ b/etc/NEWS.29 @@ -696,7 +696,9 @@ between these modes while the user is inputting a command by hitting 'duplicate-line' duplicates the current line the specified number of times. 'duplicate-dwim' duplicates the region if it is active. If not, it works like 'duplicate-line'. An active rectangular region is -duplicated on its right-hand side. +duplicated on its right-hand side. The new user option +'duplicate-line-final-position' specifies where to move point +after duplicating the line. --- ** Files with the ".eld" extension are now visited in 'lisp-data-mode'. diff --git a/lisp/misc.el b/lisp/misc.el index ab083728a69..dd4ebb4cde2 100644 --- a/lisp/misc.el +++ b/lisp/misc.el @@ -63,6 +63,19 @@ Also see the `duplicate-line' command." (+ n (point))))))) (insert string))) +(defcustom duplicate-line-final-position 0 + "Where to put point after duplicating the line with `duplicate-line'. +When 0, leave point on the original line. +When 1, move point to the first new line. +When -1, move point to the last new line. +The same column is preserved after moving to a new line." + :type '(choice (const :tag "Leave point on old line" 0) + (const :tag "Move point to first new line" 1) + (const :tag "Move point to last new line" -1) + (integer)) + :group 'editing + :version "29.1") + (defun duplicate--insert-copies (n string) "Insert N copies of STRING at point." (insert (mapconcat #'identity (make-list n string)))) @@ -71,18 +84,26 @@ Also see the `duplicate-line' command." (defun duplicate-line (&optional n) "Duplicate the current line N times. Interactively, N is the prefix numeric argument, and defaults to 1. +The user option `duplicate-line-final-position' specifies where to +move point after duplicating the line. Also see the `copy-from-above-command' command." (interactive "p") (unless n (setq n 1)) (let ((line (concat (buffer-substring (line-beginning-position) (line-end-position)) - "\n"))) - (save-excursion - (forward-line 1) - (unless (bolp) - (insert "\n")) - (duplicate--insert-copies n line)))) + "\n")) + (pos (point)) + (col (current-column))) + (forward-line 1) + (unless (bolp) + (insert "\n")) + (duplicate--insert-copies n line) + (unless (< duplicate-line-final-position 0) + (goto-char pos)) + (unless (eq duplicate-line-final-position 0) + (forward-line duplicate-line-final-position) + (move-to-column col)))) (declare-function rectangle--duplicate-right "rect" (n)) diff --git a/test/lisp/misc-tests.el b/test/lisp/misc-tests.el index f1d22e099b9..ea27ea1653b 100644 --- a/test/lisp/misc-tests.el +++ b/test/lisp/misc-tests.el @@ -88,6 +88,20 @@ (duplicate-line 2) (should (equal (buffer-string) "abc\ndefg\ndefg\ndefg\nh\n")) (should (equal (point) 7))) + ;; Duplicate a line (twice) and move point to the first duplicated line. + (with-temp-buffer + (insert "abc\ndefg\nh\n") + (goto-char 7) + (let ((duplicate-line-final-position 1)) (duplicate-line 2)) + (should (equal (buffer-string) "abc\ndefg\ndefg\ndefg\nh\n")) + (should (equal (point) 12))) + ;; Duplicate a line (twice) and move point to the last duplicated line. + (with-temp-buffer + (insert "abc\ndefg\nh\n") + (goto-char 7) + (let ((duplicate-line-final-position -1)) (duplicate-line 2)) + (should (equal (buffer-string) "abc\ndefg\ndefg\ndefg\nh\n")) + (should (equal (point) 17))) ;; Duplicate a non-terminated line. (with-temp-buffer (insert "abc") -- 2.39.2