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)
(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.
(undo-make-selective-list (min beg end) (max beg end))
buffer-undo-list)))
+;; 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))
- 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))
- ;; Skip over marker adjustments, instead relying on
- ;; finding them after (TEXT . POS) elements
- ((markerp (car-safe undo-elt))
- nil)
- (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
- (when (not (and (eq (car undo-list) nil)
- (eq undo-elt nil)))
- (setq undo-list (cons undo-elt undo-list))
- ;; If (TEXT . POS), "keep" its subsequent (MARKER
- ;; . ADJUSTMENT) whose markers haven't moved.
- (when (and (stringp (car-safe undo-elt))
- (integerp (cdr-safe undo-elt)))
- (let ((list-i (cdr undo-list-copy)))
+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
+ (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)))
- (let* ((adj-elt (pop list-i))
- (m (car adj-elt)))
- (and (eq (marker-buffer m) (current-buffer))
- (= (cdr undo-elt) m)
- (push adj-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)))
+ (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.
;; (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*
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
(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.
(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)
"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)