;; Copyright (C) 1985-1987, 1993-2014 Free Software Foundation, Inc.
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
;; Keywords: internal
;; Package: emacs
text-property `hard'.
With ARG, insert that many newlines.
-To turn off indentation by this command, disable Electric Indent mode
-\(see \\[electric-indent-mode]).
+If `electric-indent-mode' is enabled, this indents the final new line
+that it adds, and reindents the preceding line. To just insert
+a newline, use \\[electric-indent-just-newline].
Calls `auto-fill-function' if the current column number is greater
than the value of `fill-column' and ARG is nil.
column specified by the function `current-left-margin'."
(interactive "*")
(delete-horizontal-space t)
- (newline 1 t)
+ (newline nil t)
(indent-according-to-mode))
(defun reindent-then-newline-and-indent ()
(indent-according-to-mode)))
(defcustom read-quoted-char-radix 8
- "*Radix for \\[quoted-insert] and other uses of `read-quoted-char'.
+ "Radix for \\[quoted-insert] and other uses of `read-quoted-char'.
Legitimate radix values are 8, 10 and 16."
:type '(choice (const 8) (const 10) (const 16))
:group 'editing-basics)
;; (>= char ?\240)
;; (<= char ?\377))
;; (setq char (unibyte-char-to-multibyte char)))
+ (unless (characterp char)
+ (user-error "%s is not a valid character"
+ (key-description (vector char))))
(if (> arg 0)
(if (eq overwrite-mode 'overwrite-mode-binary)
(delete-char arg)))
If N is negative, delete newlines as well, leaving -N spaces.
See also `cycle-spacing'."
(interactive "*p")
- (cycle-spacing n nil t))
+ (cycle-spacing n nil 'single-shot))
(defvar cycle-spacing--context nil
"Store context used in consecutive calls to `cycle-spacing' command.
-The first time this function is run, it saves the original point
-position and original spacing around the point in this
-variable.")
+The first time `cycle-spacing' runs, it saves in this variable:
+its N argument, the original point position, and the original spacing
+around point.")
-(defun cycle-spacing (&optional n preserve-nl-back single-shot)
+(defun cycle-spacing (&optional n preserve-nl-back mode)
"Manipulate whitespace around point in a smart way.
In interactive use, this function behaves differently in successive
consecutive calls.
it deletes newlines as well, leaving -N spaces.
\(If PRESERVE-NL-BACK is non-nil, it does not delete newlines before point.)
-The second call in a sequence (or the first call if the above does
-not result in any changes) deletes all spaces.
+The second call in a sequence deletes all spaces.
The third call in a sequence restores the original whitespace (and point).
-If SINGLE-SHOT is non-nil, it only performs the first step in the sequence."
+If MODE is `single-shot', it only performs the first step in the sequence.
+If MODE is `fast' and the first step would not result in any change
+\(i.e., there are exactly (abs N) spaces around point),
+the function goes straight to the second step.
+
+Repeatedly calling the function with different values of N starts a
+new sequence each time."
(interactive "*p")
(let ((orig-pos (point))
(skip-characters (if (and n (< n 0)) " \t\n\r" " \t"))
- (n (abs (or n 1))))
+ (num (abs (or n 1))))
(skip-chars-backward (if preserve-nl-back " \t" skip-characters))
(constrain-to-field nil orig-pos)
(cond
- ;; Command run for the first time or single-shot is non-nil.
- ((or single-shot
+ ;; Command run for the first time, single-shot mode or different argument
+ ((or (eq 'single-shot mode)
(not (equal last-command this-command))
- (not cycle-spacing--context))
+ (not cycle-spacing--context)
+ (not (eq (car cycle-spacing--context) n)))
(let* ((start (point))
- (n (- n (skip-chars-forward " " (+ n (point)))))
+ (num (- num (skip-chars-forward " " (+ num (point)))))
(mid (point))
(end (progn
(skip-chars-forward skip-characters)
(setq cycle-spacing--context ;; Save for later.
;; Special handling for case where there was no space at all.
(unless (= start end)
- (cons orig-pos (buffer-substring start (point)))))
+ (cons n (cons orig-pos (buffer-substring start (point))))))
;; If this run causes no change in buffer content, delete all spaces,
;; otherwise delete all excess spaces.
- (delete-region (if (and (not single-shot) (zerop n) (= mid end))
+ (delete-region (if (and (eq mode 'fast) (zerop num) (= mid end))
start mid) end)
- (insert (make-string n ?\s))))
+ (insert (make-string num ?\s))))
;; Command run for the second time.
((not (equal orig-pos (point)))
;; Command run for the third time.
(t
- (insert (cdr cycle-spacing--context))
- (goto-char (car cycle-spacing--context))
+ (insert (cddr cycle-spacing--context))
+ (goto-char (cadr cycle-spacing--context))
(setq cycle-spacing--context nil)))))
\f
(defun beginning-of-buffer (&optional arg)
accessible part of the buffer.
If Transient Mark mode is disabled, leave mark at previous
-position, unless a \\[universal-argument] prefix is supplied.
-
-Don't use this command in Lisp programs!
-\(goto-char (point-min)) is faster."
+position, unless a \\[universal-argument] prefix is supplied."
+ (declare (interactive-only "use `(goto-char (point-min))' instead."))
(interactive "^P")
(or (consp arg)
(region-active-p)
(/ (+ 10 (* size (prefix-numeric-value arg))) 10)))
(point-min))))
(if (and arg (not (consp arg))) (forward-line 1)))
-(put 'beginning-of-buffer 'interactive-only
- "use `(goto-char (point-min))' instead.")
(defun end-of-buffer (&optional arg)
"Move point to the end of the buffer.
accessible part of the buffer.
If Transient Mark mode is disabled, leave mark at previous
-position, unless a \\[universal-argument] prefix is supplied.
-
-Don't use this command in Lisp programs!
-\(goto-char (point-max)) is faster."
+position, unless a \\[universal-argument] prefix is supplied."
+ (declare (interactive-only "use `(goto-char (point-max))' instead."))
(interactive "^P")
(or (consp arg) (region-active-p) (push-mark))
(let ((size (- (point-max) (point-min))))
;; then scroll specially to put it near, but not at, the bottom.
(overlay-recenter (point))
(recenter -3))))
-(put 'end-of-buffer 'interactive-only "use `(goto-char (point-max))' instead.")
(defcustom delete-active-region t
"Whether single-char deletion commands delete an active region.
In Overwrite mode, single character backward deletion may replace
tabs with spaces so as to back over columns, unless point is at
the end of the line."
+ (declare (interactive-only delete-char))
(interactive "p\nP")
(unless (integerp n)
(signal 'wrong-type-argument (list 'integerp n)))
(insert-char ?\s (- ocol (current-column)) nil))))
;; Otherwise, do simple deletion.
(t (delete-char (- n) killflag))))
-(put 'delete-backward-char 'interactive-only 'delete-char)
(defun delete-forward-char (n &optional killflag)
"Delete the following N characters (previous if N is negative).
Optional second arg KILLFLAG non-nil means to kill (save in kill
ring) instead of delete. Interactively, N is the prefix arg, and
KILLFLAG is set if N was explicitly specified."
+ (declare (interactive-only delete-char))
(interactive "p\nP")
(unless (integerp n)
(signal 'wrong-type-argument (list 'integerp n)))
You probably should not use this function in Lisp programs;
it is usually a mistake for a Lisp function to use any subroutine
that uses or sets the mark."
+ (declare (interactive-only t))
(interactive)
(push-mark (point))
(push-mark (point-max) nil t)
(forward-line (1- N))
If at all possible, an even better solution is to use char counts
rather than line counts."
+ (declare (interactive-only forward-line))
(interactive
(if (and current-prefix-arg (not (consp current-prefix-arg)))
(list (prefix-numeric-value current-prefix-arg))
(if (eq selective-display t)
(re-search-forward "[\n\C-m]" nil 'end (1- line))
(forward-line (1- line)))))
-(put 'goto-line 'interactive-only 'forward-line)
(defun count-words-region (start end &optional arg)
"Count the number of words in the region.
;; add it to the history.
(or (equal newcmd (car command-history))
(setq command-history (cons newcmd command-history)))
- (unwind-protect
- (progn
- ;; Trick called-interactively-p into thinking that `newcmd' is
- ;; an interactive call (bug#14136).
- (add-hook 'called-interactively-p-functions
- #'repeat-complex-command--called-interactively-skip)
- (eval newcmd))
- (remove-hook 'called-interactively-p-functions
- #'repeat-complex-command--called-interactively-skip)))
+ (apply #'funcall-interactively
+ (car newcmd)
+ (mapcar (lambda (e) (eval e t)) (cdr newcmd))))
(if command-history
(error "Argument %d is beyond length of command history" arg)
(error "There are no previous complex commands to repeat")))))
-(defun repeat-complex-command--called-interactively-skip (i _frame1 frame2)
- (and (eq 'eval (cadr frame2))
- (eq 'repeat-complex-command
- (cadr (backtrace-frame i #'called-interactively-p)))
- 1))
(defvar extended-command-history nil)
(defun execute-extended-command (prefixarg &optional command-name)
;; Based on Fexecute_extended_command in keyboard.c of Emacs.
;; Aaron S. Hawley <aaron.s.hawley(at)gmail.com> 2009-08-24
- "Read function name, then read its arguments and call it.
-
-To pass a numeric argument to the command you are invoking, specify
-the numeric argument to this command.
-
+ "Read a command name, then read the arguments and call the command.
+Interactively, to pass a prefix argument to the command you are
+invoking, give a prefix argument to `execute-extended-command'.
Noninteractively, the argument PREFIXARG is the prefix argument to
-give to the command you invoke, if it asks for an argument."
+give to the command you invoke."
(interactive (list current-prefix-arg (read-extended-command)))
;; Emacs<24 calling-convention was with a single `prefixarg' argument.
(if (null command-name)
(prog1 prefix-arg
(setq current-prefix-arg prefix-arg)
(setq prefix-arg nil)))))
- (and (symbolp cmd)
- (get cmd 'disabled)
- ;; FIXME: Weird calling convention!
- (run-hooks 'disabled-command-function))
- (let ((final cmd))
- (while
- (progn
- (setq final (indirect-function final))
- (if (autoloadp final)
- (setq final (autoload-do-load final cmd)))))
- (cond
- ((arrayp final)
- ;; If requested, place the macro in the command history. For
- ;; other sorts of commands, call-interactively takes care of this.
- (when record-flag
- (push `(execute-kbd-macro ,final ,prefixarg) command-history)
- ;; Don't keep command history around forever.
- (when (and (numberp history-length) (> history-length 0))
- (let ((cell (nthcdr history-length command-history)))
- (if (consp cell) (setcdr cell nil)))))
- (execute-kbd-macro final prefixarg))
- (t
- ;; Pass `cmd' rather than `final', for the backtrace's sake.
- (prog1 (call-interactively cmd record-flag keys)
- (when (and (symbolp cmd)
- (get cmd 'byte-obsolete-info)
- (not (get cmd 'command-execute-obsolete-warned)))
- (put cmd 'command-execute-obsolete-warned t)
- (message "%s" (macroexp--obsolete-warning
- cmd (get cmd 'byte-obsolete-info) "command")))))))))
+ (if (and (symbolp cmd)
+ (get cmd 'disabled)
+ disabled-command-function)
+ ;; FIXME: Weird calling convention!
+ (run-hooks 'disabled-command-function)
+ (let ((final cmd))
+ (while
+ (progn
+ (setq final (indirect-function final))
+ (if (autoloadp final)
+ (setq final (autoload-do-load final cmd)))))
+ (cond
+ ((arrayp final)
+ ;; If requested, place the macro in the command history. For
+ ;; other sorts of commands, call-interactively takes care of this.
+ (when record-flag
+ (push `(execute-kbd-macro ,final ,prefixarg) command-history)
+ ;; Don't keep command history around forever.
+ (when (and (numberp history-length) (> history-length 0))
+ (let ((cell (nthcdr history-length command-history)))
+ (if (consp cell) (setcdr cell nil)))))
+ (execute-kbd-macro final prefixarg))
+ (t
+ ;; Pass `cmd' rather than `final', for the backtrace's sake.
+ (prog1 (call-interactively cmd record-flag keys)
+ (when (and (symbolp cmd)
+ (get cmd 'byte-obsolete-info)
+ (not (get cmd 'command-execute-obsolete-warned)))
+ (put cmd 'command-execute-obsolete-warned t)
+ (message "%s" (macroexp--obsolete-warning
+ cmd (get cmd 'byte-obsolete-info) "command"))))))))))
\f
(defvar minibuffer-history nil
"Default minibuffer history list.
;; above when checking.
(while (eq (car list) nil)
(setq list (cdr list)))
- (puthash list (if undo-in-region t pending-undo-list)
+ (puthash list
+ ;; Prevent identity mapping. This can happen if
+ ;; consecutive nils are erroneously in undo list.
+ (if (or undo-in-region (eq list pending-undo-list))
+ t
+ pending-undo-list)
undo-equiv-table))
;; Don't specify a position in the undo record for the undo command.
;; Instead, undoing this should move point to where the change is.
(when (let ((apos (abs pos)))
(or (< apos (point-min)) (> apos (point-max))))
(error "Changes to be undone are outside visible portion of buffer"))
- (if (< pos 0)
- (progn
- (goto-char (- pos))
- (insert string))
- (goto-char pos)
- ;; Now that we record marker adjustments
- ;; (caused by deletion) for undo,
- ;; we should always insert after markers,
- ;; so that undoing the marker adjustments
- ;; put the markers back in the right place.
- (insert string)
- (goto-char pos)))
+ (let (valid-marker-adjustments)
+ ;; Check that marker adjustments which were recorded
+ ;; with the (STRING . POS) record are still valid, ie
+ ;; the markers haven't moved. We check their validity
+ ;; before reinserting the string so as we don't need to
+ ;; mind marker insertion-type.
+ (while (and (markerp (car-safe (car list)))
+ (integerp (cdr-safe (car list))))
+ (let* ((marker-adj (pop list))
+ (m (car marker-adj)))
+ (and (eq (marker-buffer m) (current-buffer))
+ (= pos m)
+ (push marker-adj valid-marker-adjustments))))
+ ;; Insert string and adjust point
+ (if (< pos 0)
+ (progn
+ (goto-char (- pos))
+ (insert string))
+ (goto-char pos)
+ (insert string)
+ (goto-char pos))
+ ;; Adjust the valid marker adjustments
+ (dolist (adj valid-marker-adjustments)
+ (set-marker (car adj)
+ (- (car adj) (cdr adj))))))
;; (MARKER . OFFSET) means a marker MARKER was adjusted by OFFSET.
(`(,(and marker (pred markerp)) . ,(and offset (pred integerp)))
+ (warn "Encountered %S entry in undo list with no matching (TEXT . POS) entry"
+ next)
+ ;; Even though these elements are not expected in the undo
+ ;; list, adjust them to be conservative for the 24.4
+ ;; release. (Bug#16818)
(when (marker-buffer marker)
(set-marker marker
(- marker offset)
(undo-make-selective-list (min beg end) (max beg end))
buffer-undo-list)))
-(defvar undo-adjusted-markers)
+;; The positions given in elements of the undo list are the positions
+;; as of the time that element was recorded to undo history. In
+;; general, subsequent buffer edits render those positions invalid in
+;; the current buffer, unless adjusted according to the intervening
+;; undo elements.
+;;
+;; Undo in region is a use case that requires adjustments to undo
+;; elements. It must adjust positions of elements in the region based
+;; on newer elements not in the region so as they may be correctly
+;; applied in the current buffer. undo-make-selective-list
+;; accomplishes this with its undo-deltas list of adjustments. An
+;; example undo history from oldest to newest:
+;;
+;; buf pos:
+;; 123456789 buffer-undo-list undo-deltas
+;; --------- ---------------- -----------
+;; aaa (1 . 4) (1 . -3)
+;; aaba (3 . 4) N/A (in region)
+;; ccaaba (1 . 3) (1 . -2)
+;; ccaabaddd (7 . 10) (7 . -3)
+;; ccaabdd ("ad" . 6) (6 . 2)
+;; ccaabaddd (6 . 8) (6 . -2)
+;; | |<-- region: "caab", from 2 to 6
+;;
+;; When the user starts a run of undos in region,
+;; undo-make-selective-list is called to create the full list of in
+;; region elements. Each element is adjusted forward chronologically
+;; through undo-deltas to determine if it is in the region.
+;;
+;; In the above example, the insertion of "b" is (3 . 4) in the
+;; buffer-undo-list. The undo-delta (1 . -2) causes (3 . 4) to become
+;; (5 . 6). The next three undo-deltas cause no adjustment, so (5
+;; . 6) is assessed as in the region and placed in the selective list.
+;; Notably, the end of region itself adjusts from "2 to 6" to "2 to 5"
+;; due to the selected element. The "b" insertion is the only element
+;; fully in the region, so in this example undo-make-selective-list
+;; returns (nil (5 . 6)).
+;;
+;; The adjustment of the (7 . 10) insertion of "ddd" shows an edge
+;; case. It is adjusted through the undo-deltas: ((6 . 2) (6 . -2)).
+;; Normally an undo-delta of (6 . 2) would cause positions after 6 to
+;; adjust by 2. However, they shouldn't adjust to less than 6, so (7
+;; . 10) adjusts to (6 . 8) due to the first undo delta.
+;;
+;; More interesting is how to adjust the "ddd" insertion due to the
+;; next undo-delta: (6 . -2), corresponding to reinsertion of "ad".
+;; If the reinsertion was a manual retyping of "ad", then the total
+;; adjustment should be (7 . 10) -> (6 . 8) -> (8 . 10). However, if
+;; the reinsertion was due to undo, one might expect the first "d"
+;; character would again be a part of the "ddd" text, meaning its
+;; total adjustment would be (7 . 10) -> (6 . 8) -> (7 . 10).
+;;
+;; undo-make-selective-list assumes in this situation that "ad" was a
+;; new edit, even if it was inserted because of an undo.
+;; Consequently, if the user undos in region "8 to 10" of the
+;; "ccaabaddd" buffer, they could be surprised that it becomes
+;; "ccaabad", as though the first "d" became detached from the
+;; original "ddd" insertion. This quirk is a FIXME.
(defun undo-make-selective-list (start end)
"Return a list of undo elements for the region START to END.
-The elements come from `buffer-undo-list', but we keep only
-the elements inside this region, and discard those outside this region.
-If we find an element that crosses an edge of this region,
-we stop and ignore all further elements."
- (let ((undo-list-copy (undo-copy-list buffer-undo-list))
- (undo-list (list nil))
- undo-adjusted-markers
- some-rejected
- undo-elt temp-undo-list delta)
- (while undo-list-copy
- (setq undo-elt (car undo-list-copy))
- (let ((keep-this
- (cond ((and (consp undo-elt) (eq (car undo-elt) t))
- ;; This is a "was unmodified" element.
- ;; Keep it if we have kept everything thus far.
- (not some-rejected))
- (t
- (undo-elt-in-region undo-elt start end)))))
- (if keep-this
- (progn
- (setq end (+ end (cdr (undo-delta undo-elt))))
- ;; Don't put two nils together in the list
- (if (not (and (eq (car undo-list) nil)
- (eq undo-elt nil)))
- (setq undo-list (cons undo-elt undo-list))))
- (if (undo-elt-crosses-region undo-elt start end)
- (setq undo-list-copy nil)
- (setq some-rejected t)
- (setq temp-undo-list (cdr undo-list-copy))
- (setq delta (undo-delta undo-elt))
-
- (when (/= (cdr delta) 0)
- (let ((position (car delta))
- (offset (cdr delta)))
-
- ;; Loop down the earlier events adjusting their buffer
- ;; positions to reflect the fact that a change to the buffer
- ;; isn't being undone. We only need to process those element
- ;; types which undo-elt-in-region will return as being in
- ;; the region since only those types can ever get into the
- ;; output
-
- (while temp-undo-list
- (setq undo-elt (car temp-undo-list))
- (cond ((integerp undo-elt)
- (if (>= undo-elt position)
- (setcar temp-undo-list (- undo-elt offset))))
- ((atom undo-elt) nil)
- ((stringp (car undo-elt))
- ;; (TEXT . POSITION)
- (let ((text-pos (abs (cdr undo-elt)))
- (point-at-end (< (cdr undo-elt) 0 )))
- (if (>= text-pos position)
- (setcdr undo-elt (* (if point-at-end -1 1)
- (- text-pos offset))))))
- ((integerp (car undo-elt))
- ;; (BEGIN . END)
- (when (>= (car undo-elt) position)
- (setcar undo-elt (- (car undo-elt) offset))
- (setcdr undo-elt (- (cdr undo-elt) offset))))
- ((null (car undo-elt))
- ;; (nil PROPERTY VALUE BEG . END)
- (let ((tail (nthcdr 3 undo-elt)))
- (when (>= (car tail) position)
- (setcar tail (- (car tail) offset))
- (setcdr tail (- (cdr tail) offset))))))
- (setq temp-undo-list (cdr temp-undo-list))))))))
- (setq undo-list-copy (cdr undo-list-copy)))
- (nreverse undo-list)))
+The elements come from `buffer-undo-list', but we keep only the
+elements inside this region, and discard those outside this
+region. The elements' positions are adjusted so as the returned
+list can be applied to the current buffer."
+ (let ((ulist buffer-undo-list)
+ ;; A list of position adjusted undo elements in the region.
+ (selective-list (list nil))
+ ;; A list of undo-deltas for out of region undo elements.
+ undo-deltas
+ undo-elt)
+ (while ulist
+ (when undo-no-redo
+ (while (gethash ulist undo-equiv-table)
+ (setq ulist (gethash ulist undo-equiv-table))))
+ (setq undo-elt (car ulist))
+ (cond
+ ((null undo-elt)
+ ;; Don't put two nils together in the list
+ (when (car selective-list)
+ (push nil selective-list)))
+ ((and (consp undo-elt) (eq (car undo-elt) t))
+ ;; This is a "was unmodified" element. Keep it
+ ;; if we have kept everything thus far.
+ (when (not undo-deltas)
+ (push undo-elt selective-list)))
+ ;; Skip over marker adjustments, instead relying
+ ;; on finding them after (TEXT . POS) elements
+ ((markerp (car-safe undo-elt))
+ nil)
+ (t
+ (let ((adjusted-undo-elt (undo-adjust-elt undo-elt
+ undo-deltas)))
+ (if (undo-elt-in-region adjusted-undo-elt start end)
+ (progn
+ (setq end (+ end (cdr (undo-delta adjusted-undo-elt))))
+ (push adjusted-undo-elt selective-list)
+ ;; Keep (MARKER . ADJUSTMENT) if their (TEXT . POS) was
+ ;; kept. primitive-undo may discard them later.
+ (when (and (stringp (car-safe adjusted-undo-elt))
+ (integerp (cdr-safe adjusted-undo-elt)))
+ (let ((list-i (cdr ulist)))
+ (while (markerp (car-safe (car list-i)))
+ (push (pop list-i) selective-list)))))
+ (let ((delta (undo-delta undo-elt)))
+ (when (/= 0 (cdr delta))
+ (push delta undo-deltas)))))))
+ (pop ulist))
+ (nreverse selective-list)))
(defun undo-elt-in-region (undo-elt start end)
"Determine whether UNDO-ELT falls inside the region START ... END.
-If it crosses the edge, we return nil."
+If it crosses the edge, we return nil.
+
+Generally this function is not useful for determining
+whether (MARKER . ADJUSTMENT) undo elements are in the region,
+because markers can be arbitrarily relocated. Instead, pass the
+marker adjustment's corresponding (TEXT . POS) element."
(cond ((integerp undo-elt)
(and (>= undo-elt start)
(<= undo-elt end)))
((stringp (car undo-elt))
;; (TEXT . POSITION)
(and (>= (abs (cdr undo-elt)) start)
- (< (abs (cdr undo-elt)) end)))
+ (<= (abs (cdr undo-elt)) end)))
((and (consp undo-elt) (markerp (car undo-elt)))
- ;; This is a marker-adjustment element (MARKER . ADJUSTMENT).
- ;; See if MARKER is inside the region.
- (let ((alist-elt (assq (car undo-elt) undo-adjusted-markers)))
- (unless alist-elt
- (setq alist-elt (cons (car undo-elt)
- (marker-position (car undo-elt))))
- (setq undo-adjusted-markers
- (cons alist-elt undo-adjusted-markers)))
- (and (cdr alist-elt)
- (>= (cdr alist-elt) start)
- (<= (cdr alist-elt) end))))
+ ;; (MARKER . ADJUSTMENT)
+ (<= start (car undo-elt) end))
((null (car undo-elt))
;; (nil PROPERTY VALUE BEG . END)
(let ((tail (nthcdr 3 undo-elt)))
;; (BEGIN . END)
(and (< (car undo-elt) end)
(> (cdr undo-elt) start)))))
+(make-obsolete 'undo-elt-crosses-region nil "24.5")
+
+(defun undo-adjust-elt (elt deltas)
+ "Return adjustment of undo element ELT by the undo DELTAS
+list."
+ (pcase elt
+ ;; POSITION
+ ((pred integerp)
+ (undo-adjust-pos elt deltas))
+ ;; (BEG . END)
+ (`(,(and beg (pred integerp)) . ,(and end (pred integerp)))
+ (undo-adjust-beg-end beg end deltas))
+ ;; (TEXT . POSITION)
+ (`(,(and text (pred stringp)) . ,(and pos (pred integerp)))
+ (cons text (* (if (< pos 0) -1 1)
+ (undo-adjust-pos (abs pos) deltas))))
+ ;; (nil PROPERTY VALUE BEG . END)
+ (`(nil . ,(or `(,prop ,val ,beg . ,end) pcase--dontcare))
+ `(nil ,prop ,val . ,(undo-adjust-beg-end beg end deltas)))
+ ;; (apply DELTA START END FUN . ARGS)
+ ;; FIXME
+ ;; All others return same elt
+ (_ elt)))
+
+;; (BEG . END) can adjust to the same positions, commonly when an
+;; insertion was undone and they are out of region, for example:
+;;
+;; buf pos:
+;; 123456789 buffer-undo-list undo-deltas
+;; --------- ---------------- -----------
+;; [...]
+;; abbaa (2 . 4) (2 . -2)
+;; aaa ("bb" . 2) (2 . 2)
+;; [...]
+;;
+;; "bb" insertion (2 . 4) adjusts to (2 . 2) because of the subsequent
+;; undo. Further adjustments to such an element should be the same as
+;; for (TEXT . POSITION) elements. The options are:
+;;
+;; 1: POSITION adjusts using <= (use-< nil), resulting in behavior
+;; analogous to marker insertion-type t.
+;;
+;; 2: POSITION adjusts using <, resulting in behavior analogous to
+;; marker insertion-type nil.
+;;
+;; There was no strong reason to prefer one or the other, except that
+;; the first is more consistent with prior undo in region behavior.
+(defun undo-adjust-beg-end (beg end deltas)
+ "Return cons of adjustments to BEG and END by the undo DELTAS
+list."
+ (let ((adj-beg (undo-adjust-pos beg deltas)))
+ ;; Note: option 2 above would be like (cons (min ...) adj-end)
+ (cons adj-beg
+ (max adj-beg (undo-adjust-pos end deltas t)))))
+
+(defun undo-adjust-pos (pos deltas &optional use-<)
+ "Return adjustment of POS by the undo DELTAS list, comparing
+with < or <= based on USE-<."
+ (dolist (d deltas pos)
+ (when (if use-<
+ (< (car d) pos)
+ (<= (car d) pos))
+ (setq pos
+ ;; Don't allow pos to become less than the undo-delta
+ ;; position. This edge case is described in the overview
+ ;; comments.
+ (max (car d) (- pos (cdr d)))))))
;; Return the first affected buffer position and the delta for an undo element
;; delta is defined as the change in subsequent buffer positions if we *did*
File names in INFILE and BUFFER are handled normally, but file
names in ARGS should be relative to `default-directory', as they
-are passed to the process verbatim. \(This is a difference to
+are passed to the process verbatim. (This is a difference to
`call-process' which does not support file handlers for INFILE
-and BUFFER.\)
+and BUFFER.)
Some file handlers might not support all variants, for example
they might behave as if DISPLAY was nil, regardless of the actual
(defvar process-menu-query-only nil)
+(defvar process-menu-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [?d] 'process-menu-delete-process)
+ map))
+
(define-derived-mode process-menu-mode tabulated-list-mode "Process Menu"
"Major mode for listing the processes called by Emacs."
(setq tabulated-list-format [("Process" 15 t)
(add-hook 'tabulated-list-revert-hook 'list-processes--refresh nil t)
(tabulated-list-init-header))
+(defun process-menu-delete-process ()
+ "Kill process at point in a `list-processes' buffer."
+ (interactive)
+ (delete-process (tabulated-list-get-id))
+ (revert-buffer))
+
(defun list-processes--refresh ()
"Recompute the list of processes for the Process List buffer.
Also, delete any process that is exited or signaled."
be copied into other buffers."
(funcall filter-buffer-substring-function beg end delete))
-;; FIXME: `with-wrapper-hook' is obsolete
(defun buffer-substring--filter (beg end &optional delete)
(with-wrapper-hook filter-buffer-substring-functions (beg end delete)
(cond
"Kill current line.
With prefix ARG, kill that many lines starting from the current line.
If ARG is negative, kill backward. Also kill the preceding newline.
-\(This is meant to make \\[repeat] work well with negative arguments.\)
+\(This is meant to make \\[repeat] work well with negative arguments.)
If ARG is zero, kill current line but exclude the trailing newline."
(interactive "p")
(or arg (setq arg 1))
(defun insert-buffer (buffer)
"Insert after point the contents of BUFFER.
Puts mark after the inserted text.
-BUFFER may be a buffer or a buffer name.
-
-This function is meant for the user to run interactively.
-Don't call it from programs: use `insert-buffer-substring' instead!"
+BUFFER may be a buffer or a buffer name."
+ (declare (interactive-only insert-buffer-substring))
(interactive
(list
(progn
(insert-buffer-substring (get-buffer buffer))
(point)))
nil)
-(put 'insert-buffer 'interactive-only 'insert-buffer-substring)
(defun append-to-buffer (buffer start end)
"Append to specified buffer the text of the region.
(if (eq (car-safe transient-mark-mode) 'only)
(setq transient-mark-mode (cdr transient-mark-mode)))
(setq mark-active nil)
- (run-hooks 'deactivate-mark-hook))))
+ (run-hooks 'deactivate-mark-hook))
+ (redisplay--update-region-highlight (selected-window))))
(defun activate-mark (&optional no-tmm)
"Activate the mark.
If NO-TMM is non-nil, leave `transient-mark-mode' alone."
(when (mark t)
- (unless (and mark-active transient-mark-mode)
- (force-mode-line-update)) ;Refresh toolbar (bug#16382).
- (setq mark-active t)
- (unless (or transient-mark-mode no-tmm)
- (setq transient-mark-mode 'lambda))
- (run-hooks 'activate-mark-hook)))
+ (unless (region-active-p)
+ (force-mode-line-update) ;Refresh toolbar (bug#16382).
+ (setq mark-active t)
+ (unless (or transient-mark-mode no-tmm)
+ (setq transient-mark-mode 'lambda))
+ (run-hooks 'activate-mark-hook))))
(defun set-mark (pos)
"Set this buffer's mark to POS. Don't use this function!
store it in a Lisp variable. Example:
(let ((beg (point))) (forward-line 1) (delete-region beg (point)))."
-
- (set-marker (mark-marker) pos (current-buffer))
(if pos
- (activate-mark 'no-tmm)
+ (progn
+ (set-marker (mark-marker) pos (current-buffer))
+ (activate-mark 'no-tmm))
;; Normally we never clear mark-active except in Transient Mark mode.
;; But when we actually clear out the mark value too, we must
;; clear mark-active in any mode.
- (deactivate-mark t)))
+ (deactivate-mark t)
+ ;; `deactivate-mark' sometimes leaves mark-active non-nil, but
+ ;; it should never be nil if the mark is nil.
+ (setq mark-active nil)
+ (set-marker (mark-marker) nil)))
(defcustom use-empty-active-region nil
"Whether \"region-aware\" commands should act on empty regions.
mode is enabled. Usually, such commands should use
`use-region-p' instead of this function, because `use-region-p'
also checks the value of `use-empty-active-region'."
- (and transient-mark-mode mark-active))
+ (and transient-mark-mode mark-active
+ ;; FIXME: Somehow we sometimes end up with mark-active non-nil but
+ ;; without the mark being set (e.g. bug#17324). We really should fix
+ ;; that problem, but in the mean time, let's make sure we don't say the
+ ;; region is active when there's no mark.
+ (mark)))
(defvar redisplay-unhighlight-region-function
(funcall redisplay-unhighlight-region-function rol)
(overlay-put nrol 'window window)
(overlay-put nrol 'face 'region)
+ ;; Normal priority so that a large region doesn't hide all the
+ ;; overlays within it, but high secondary priority so that if it
+ ;; ends/starts in the middle of a small overlay, that small overlay
+ ;; won't hide the region's boundaries.
+ (overlay-put nrol 'priority '(nil . 100))
nrol)
(unless (and (eq (overlay-buffer rol) (current-buffer))
(eq (overlay-start rol) start)
(defun pop-to-mark-command ()
"Jump to mark, and pop a new position for mark off the ring.
-\(Does not affect global mark ring\)."
+\(Does not affect global mark ring)."
(interactive)
(if (null (mark t))
(error "No mark set in this buffer")
When Transient Mark Mode is off, immediately repeating this
command activates `transient-mark-mode' temporarily.
-With prefix argument \(e.g., \\[universal-argument] \\[set-mark-command]\), \
+With prefix argument (e.g., \\[universal-argument] \\[set-mark-command]), \
jump to the mark, and set the mark from
-position popped off the local mark ring \(this does not affect the global
-mark ring\). Use \\[pop-global-mark] to jump to a mark popped off the global
-mark ring \(see `pop-global-mark'\).
+position popped off the local mark ring (this does not affect the global
+mark ring). Use \\[pop-global-mark] to jump to a mark popped off the global
+mark ring (see `pop-global-mark').
If `set-mark-command-repeat-pop' is non-nil, repeating
the \\[set-mark-command] command with no prefix argument pops the next position
The goal column is stored in the variable `goal-column', which is nil
when there is no goal column. Note that setting `goal-column'
overrides `line-move-visual' and causes this command to move by buffer
-lines rather than by display lines.
-
-If you are thinking of using this in a Lisp program, consider
-using `forward-line' instead. It is usually easier to use
-and more reliable (no dependence on goal column, etc.)."
+lines rather than by display lines."
+ (declare (interactive-only forward-line))
(interactive "^p\np")
(or arg (setq arg 1))
(if (and next-line-add-newlines (= arg 1))
(signal (car err) (cdr err))))
(line-move arg nil nil try-vscroll)))
nil)
-(put 'next-line 'interactive-only 'forward-line)
(defun previous-line (&optional arg try-vscroll)
"Move cursor vertically up ARG lines.
The goal column is stored in the variable `goal-column', which is nil
when there is no goal column. Note that setting `goal-column'
overrides `line-move-visual' and causes this command to move by buffer
-lines rather than by display lines.
-
-If you are thinking of using this in a Lisp program, consider using
-`forward-line' with a negative argument instead. It is usually easier
-to use and more reliable (no dependence on goal column, etc.)."
+lines rather than by display lines."
+ (declare (interactive-only
+ "use `forward-line' with negative argument instead."))
(interactive "^p\np")
(or arg (setq arg 1))
(if (called-interactively-p 'interactive)
(signal (car err) (cdr err))))
(line-move (- arg) nil nil try-vscroll))
nil)
-(put 'previous-line 'interactive-only
- "use `forward-line' with negative argument instead.")
(defcustom track-eol nil
"Non-nil means vertical motion starting at end of line keeps to ends of lines.
`most-positive-fixnum'.")
(defcustom line-move-ignore-invisible t
- "Non-nil means \\[next-line] and \\[previous-line] ignore invisible lines.
+ "Non-nil means commands that move by lines ignore invisible newlines.
+When this option is non-nil, \\[next-line], \\[previous-line], \\[move-end-of-line], and \\[move-beginning-of-line] behave
+as if newlines that are invisible didn't exist, and count
+only visible newlines. Thus, moving across across 2 newlines
+one of which is invisible will be counted as a one-line move.
+Also, a non-nil value causes invisible text to be ignored when
+counting columns for the purposes of keeping point in the same
+column by \\[next-line] and \\[previous-line].
+
Outline mode sets this."
:type 'boolean
:group 'editing-basics)
;; a cleaner solution to the problem of making C-n do something
;; useful given a tall image.
(defun line-move (arg &optional noerror to-end try-vscroll)
+ "Move forward ARG lines.
+If NOERROR, don't signal an error if we can't move ARG lines.
+TO-END is unused.
+TRY-VSCROLL controls whether to vscroll tall lines: if either
+`auto-window-vscroll' or TRY-VSCROLL is nil, this function will
+not vscroll."
(if noninteractive
(forward-line arg)
(unless (and auto-window-vscroll try-vscroll
;; Arg says how many lines to move. The value is t if we can move the
;; specified number of lines.
(defun line-move-visual (arg &optional noerror)
+ "Move ARG lines forward.
+If NOERROR, don't signal an error if we can't move that many lines."
(let ((opoint (point))
(hscroll (window-hscroll))
target-hscroll)
;; the middle of a continued line. When we get to
;; line-move-finish, point is at the start of a new *screen*
;; line but the same text line; then line-move-to-column would
- ;; move us backwards. Test using C-n with point on the "x" in
+ ;; move us backwards. Test using C-n with point on the "x" in
;; (insert "a" (propertize "x" 'field t) (make-string 89 ?y))
(and forward
(< (point) old)
:group 'paren-matching)
(defcustom blink-matching-paren t
- "Non-nil means show matching open-paren when close-paren is inserted."
- :type 'boolean
+ "Non-nil means show matching open-paren when close-paren is inserted.
+If t, highlight the paren. If `jump', move cursor to its position."
+ :type '(choice
+ (const :tag "Disable" nil)
+ (const :tag "Highlight" t)
+ (const :tag "Move cursor" jump))
:group 'paren-blinking)
(defcustom blink-matching-paren-on-screen t
(not blink-matching-paren-dont-ignore-comments))))
(condition-case ()
(progn
+ (syntax-propertize (point))
(forward-sexp -1)
;; backward-sexp skips backward over prefix chars,
;; so move back to the matching paren.
(message "No matching parenthesis found"))))
((not blinkpos) nil)
((pos-visible-in-window-p blinkpos)
- ;; Matching open within window, temporarily highlight char
- ;; after blinkpos but only if `blink-matching-paren-on-screen'
+ ;; Matching open within window, temporarily move to or highlight
+ ;; char after blinkpos but only if `blink-matching-paren-on-screen'
;; is non-nil.
(and blink-matching-paren-on-screen
(not show-paren-mode)
- (unwind-protect
- (progn
- (move-overlay blink-matching--overlay blinkpos (1+ blinkpos)
- (current-buffer))
+ (if (eq blink-matching-paren 'jump)
+ (save-excursion
+ (goto-char blinkpos)
(sit-for blink-matching-delay))
- (delete-overlay blink-matching--overlay))))
+ (unwind-protect
+ (progn
+ (move-overlay blink-matching--overlay blinkpos (1+ blinkpos)
+ (current-buffer))
+ (sit-for blink-matching-delay))
+ (delete-overlay blink-matching--overlay)))))
(t
(save-excursion
(goto-char blinkpos)
(deactivate-mark))
(if (fboundp 'kmacro-keyboard-quit)
(kmacro-keyboard-quit))
+ (when completion-in-region-mode
+ (completion-in-region-mode -1))
(setq defining-kbd-macro nil)
(let ((debug-on-quit nil))
(signal 'quit nil)))
(defvar completion-list-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map [mouse-2] 'mouse-choose-completion)
+ (define-key map [mouse-2] 'choose-completion)
(define-key map [follow-link] 'mouse-face)
(define-key map [down-mouse-2] nil)
(define-key map "\C-m" 'choose-completion)
(setq n (1+ n))))))
(defun choose-completion (&optional event)
- "Choose the completion at point."
+ "Choose the completion at point.
+If EVENT, use EVENT's position to determine the starting position."
(interactive (list last-nonmenu-event))
;; In case this is run via the mouse, give temporary modes such as
;; isearch a chance to turn off.
(defvar choose-completion-string-functions nil
"Functions that may override the normal insertion of a completion choice.
-These functions are called in order with four arguments:
+These functions are called in order with three arguments:
CHOICE - the string to insert in the buffer,
BUFFER - the buffer in which the choice should be inserted,
-MINI-P - non-nil if BUFFER is a minibuffer, and
-BASE-SIZE - the number of characters in BUFFER before
-the string being completed.
+BASE-POSITION - where to insert the completion.
If a function in the list returns non-nil, that function is supposed
to have inserted the CHOICE in the BUFFER, and possibly exited
"Major mode for buffers showing lists of possible completions.
Type \\<completion-list-mode-map>\\[choose-completion] in the completion list\
to select the completion near point.
-Use \\<completion-list-mode-map>\\[mouse-choose-completion] to select one\
- with the mouse.
+Or click to select one with the mouse.
\\{completion-list-mode-map}"
(set (make-local-variable 'completion-base-size) nil))
(goto-char (point-min))
(if (display-mouse-p)
(insert (substitute-command-keys
- "Click \\[mouse-choose-completion] on a completion to select it.\n")))
+ "Click on a completion to select it.\n")))
(insert (substitute-command-keys
"In this buffer, type \\[choose-completion] to \
select the completion near point.\n\n"))))))
command-name)))))))
\f
-;; This is here because files in obsolete/ are not scanned for autoloads.
-
-(defvar iswitchb-mode nil "\
-Non-nil if Iswitchb mode is enabled.
-See the command `iswitchb-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `iswitchb-mode'.")
-
-(custom-autoload 'iswitchb-mode "iswitchb" nil)
-
-(autoload 'iswitchb-mode "iswitchb" "\
-Toggle Iswitchb mode.
-With a prefix argument ARG, enable Iswitchb mode if ARG is
-positive, and disable it otherwise. If called from Lisp, enable
-the mode if ARG is omitted or nil.
-
-Iswitchb mode is a global minor mode that enables switching
-between buffers using substrings. See `iswitchb' for details.
-
-\(fn &optional ARG)" t nil)
-
-(make-obsolete 'iswitchb-mode
- "use `icomplete-mode' or `ido-mode' instead." "24.4")
-\f
(provide 'simple)