summaryrefslogtreecommitdiff
path: root/lisp/misc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/misc.el')
-rw-r--r--lisp/misc.el65
1 files changed, 50 insertions, 15 deletions
diff --git a/lisp/misc.el b/lisp/misc.el
index b36ca6416d9..fb40d1c16a3 100644
--- a/lisp/misc.el
+++ b/lisp/misc.el
@@ -76,6 +76,10 @@ The same column is preserved after moving to a new line."
: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))))
+
;;;###autoload
(defun duplicate-line (&optional n)
"Duplicate the current line N times.
@@ -86,21 +90,33 @@ Also see the `copy-from-above-command' command."
(interactive "p")
(unless n
(setq n 1))
- (let ((line (buffer-substring (line-beginning-position) (line-end-position)))
+ (let ((line (concat (buffer-substring (line-beginning-position)
+ (line-end-position))
+ "\n"))
(pos (point))
(col (current-column)))
(forward-line 1)
(unless (bolp)
(insert "\n"))
- (dotimes (_ n)
- (insert line "\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))
+(defcustom duplicate-region-final-position 0
+ "Where the region ends up after duplicating a region with `duplicate-dwim'.
+When 0, leave the region in place.
+When 1, put the region around the first copy.
+When -1, put the region around the last copy."
+ :type '(choice (const :tag "Leave region in place" 0)
+ (const :tag "Put region around first copy" 1)
+ (const :tag "Put region around last copy" -1))
+ :group 'editing
+ :version "30.1")
+
+(declare-function rectangle--duplicate-right "rect" (n displacement))
;; `duplicate-dwim' preserves an active region and changes the buffer
;; outside of it: disregard the region when immediately undoing the
@@ -113,25 +129,40 @@ Also see the `copy-from-above-command' command."
If the region is inactive, duplicate the current line (like `duplicate-line').
Otherwise, duplicate the region, which remains active afterwards.
If the region is rectangular, duplicate on its right-hand side.
-Interactively, N is the prefix numeric argument, and defaults to 1."
+Interactively, N is the prefix numeric argument, and defaults to 1.
+The variables `duplicate-line-final-position' and
+`duplicate-region-final-position' control the position of point
+and the region after the duplication."
(interactive "p")
(unless n
(setq n 1))
(cond
+ ((<= n 0) nil)
;; Duplicate rectangle.
((bound-and-true-p rectangle-mark-mode)
- (rectangle--duplicate-right n)
+ (rectangle--duplicate-right n
+ (if (< duplicate-region-final-position 0)
+ n
+ duplicate-region-final-position))
(setq deactivate-mark nil))
;; Duplicate (contiguous) region.
((use-region-p)
(let* ((beg (region-beginning))
(end (region-end))
- (text (buffer-substring beg end)))
+ (text (buffer-substring beg end))
+ (pt (point))
+ (mk (mark)))
(save-excursion
(goto-char end)
- (dotimes (_ n)
- (insert text))))
+ (duplicate--insert-copies n text))
+ (let* ((displace (if (< duplicate-region-final-position 0)
+ n
+ duplicate-region-final-position))
+ (d (* displace (- end beg))))
+ (unless (zerop d)
+ (push-mark (+ mk d))
+ (goto-char (+ pt d)))))
(setq deactivate-mark nil))
;; Duplicate line.
@@ -187,18 +218,22 @@ is an upper-case character."
(upcase-region (point) (progn (forward-char arg) (point)))))
;;;###autoload
-(defun forward-to-word (arg)
- "Move forward until encountering the beginning of a word.
-With argument, do this that many times."
+(defun forward-to-word (&optional arg)
+ "Move forward until encountering the beginning of the ARGth word.
+ARG defaults to 1. When called interactively, ARG is the prefix
+numeric argument."
(interactive "^p")
+ (unless arg (setq arg 1))
(or (re-search-forward (if (> arg 0) "\\W\\b" "\\b\\W") nil t arg)
(goto-char (if (> arg 0) (point-max) (point-min)))))
;;;###autoload
-(defun backward-to-word (arg)
- "Move backward until encountering the end of a word.
-With argument, do this that many times."
+(defun backward-to-word (&optional arg)
+ "Move backward until encountering the end of the ARGth word.
+ARG defaults to 1. When called interactively, ARG is the prefix
+numeric argument."
(interactive "^p")
+ (unless arg (setq arg 1))
(forward-to-word (- arg)))
;;;###autoload