(put-text-property from (point) 'rear-nonsticky
(cons 'hard sticky)))))
-(defun open-line (n)
+(declare-function electric-indent-just-newline "electric")
+(defun open-line (n &optional interactive)
"Insert a newline and leave point before it.
-If there is a fill prefix and/or a `left-margin', insert them
-on the new line if the line would have been blank.
-With arg N, insert N newlines."
- (interactive "*p")
+If `electric-indent-mode' is enabled, indent the new line if it's
+not empty.
+If there is a fill prefix and/or a `left-margin', insert them on
+the new line. If the old line would have been blank, insert them
+on the old line as well.
+
+With arg N, insert N newlines.
+A non-nil INTERACTIVE argument means to run the `post-self-insert-hook'."
+ (interactive "*p\np")
(let* ((do-fill-prefix (and fill-prefix (bolp)))
(do-left-margin (and (bolp) (> (current-left-margin) 0)))
(loc (point-marker))
- ;; Don't expand an abbrev before point.
+ ;; Don't expand an abbrev before point.
(abbrev-mode nil))
- (newline n)
+ (if (and interactive
+ (looking-at-p "[[:space:]]*$"))
+ (electric-indent-just-newline n)
+ (newline n interactive))
(goto-char loc)
(while (> n 0)
(cond ((bolp)
(forward-line 1)
(setq n (1- n)))
(goto-char loc)
+ ;; Necessary in case a margin or prefix was inserted.
(end-of-line)))
(defun split-line (&optional arg)
If the buffer is narrowed, this command uses the beginning of the
accessible part of the buffer.
-If Transient Mark mode is disabled, leave mark at previous
-position, unless a \\[universal-argument] prefix is supplied."
+Push mark at previous position, unless either a \\[universal-argument] prefix
+is supplied, or Transient Mark mode is enabled and the mark is active."
(declare (interactive-only "use `(goto-char (point-min))' instead."))
(interactive "^P")
(or (consp arg)
If the buffer is narrowed, this command uses the end of the
accessible part of the buffer.
-If Transient Mark mode is disabled, leave mark at previous
-position, unless a \\[universal-argument] prefix is supplied."
+Push mark at previous position, unless either a \\[universal-argument] prefix
+is supplied, or Transient Mark mode is enabled and the mark is active."
(declare (interactive-only "use `(goto-char (point-max))' instead."))
(interactive "^P")
(or (consp arg) (region-active-p) (push-mark))
(symbol-name function) typed))))
(when binding
(with-temp-message
- (format "You can run the command `%s' with %s"
- function
- (if (stringp binding)
- (concat "M-x " binding " RET")
- (key-description binding)))
+ (format-message "You can run the command `%s' with %s"
+ function
+ (if (stringp binding)
+ (concat "M-x " binding " RET")
+ (key-description binding)))
(sit-for (if (numberp suggest-key-bindings)
suggest-key-bindings
2))))))))
a special event, so ignore the prefix argument and don't clear it."
(setq debug-on-next-call nil)
(let ((prefixarg (unless special
+ ;; FIXME: This should probably be done around
+ ;; pre-command-hook rather than here!
(prog1 prefix-arg
(setq current-prefix-arg prefix-arg)
- (setq prefix-arg nil)))))
+ (setq prefix-arg nil)
+ (when current-prefix-arg
+ (prefix-command-update))))))
(if (and (symbolp cmd)
(get cmd 'disabled)
disabled-command-function)
'(0 . 0)))
'(0 . 0)))
+;;; Default undo-boundary addition
+;;
+;; This section adds a new undo-boundary at either after a command is
+;; called or in some cases on a timer called after a change is made in
+;; any buffer.
+(defvar-local undo-auto--last-boundary-cause nil
+ "Describe the cause of the last undo-boundary.
+
+If `explicit', the last boundary was caused by an explicit call to
+`undo-boundary', that is one not called by the code in this
+section.
+
+If it is equal to `timer', then the last boundary was inserted
+by `undo-auto--boundary-timer'.
+
+If it is equal to `command', then the last boundary was inserted
+automatically after a command, that is by the code defined in
+this section.
+
+If it is equal to a list, then the last boundary was inserted by
+an amalgamating command. The car of the list is the number of
+times an amalgamating command has been called, and the cdr are the
+buffers that were changed during the last command.")
+
+(defvar undo-auto--current-boundary-timer nil
+ "Current timer which will run `undo-auto--boundary-timer' or nil.
+
+If set to non-nil, this will effectively disable the timer.")
+
+(defvar undo-auto--this-command-amalgamating nil
+ "Non-nil if `this-command' should be amalgamated.
+This variable is set to nil by `undo-auto--boundaries' and is set
+by `undo-auto--amalgamate'." )
+
+(defun undo-auto--needs-boundary-p ()
+ "Return non-nil if `buffer-undo-list' needs a boundary at the start."
+ (car-safe buffer-undo-list))
+
+(defun undo-auto--last-boundary-amalgamating-number ()
+ "Return the number of amalgamating last commands or nil.
+Amalgamating commands are, by default, either
+`self-insert-command' and `delete-char', but can be any command
+that calls `undo-auto--amalgamate'."
+ (car-safe undo-auto--last-boundary-cause))
+
+(defun undo-auto--ensure-boundary (cause)
+ "Add an `undo-boundary' to the current buffer if needed.
+REASON describes the reason that the boundary is being added; see
+`undo-auto--last-boundary' for more information."
+ (when (and
+ (undo-auto--needs-boundary-p))
+ (let ((last-amalgamating
+ (undo-auto--last-boundary-amalgamating-number)))
+ (undo-boundary)
+ (setq undo-auto--last-boundary-cause
+ (if (eq 'amalgamate cause)
+ (cons
+ (if last-amalgamating (1+ last-amalgamating) 0)
+ undo-auto--undoably-changed-buffers)
+ cause)))))
+
+(defun undo-auto--boundaries (cause)
+ "Check recently changed buffers and add a boundary if necessary.
+REASON describes the reason that the boundary is being added; see
+`undo-last-boundary' for more information."
+ (dolist (b undo-auto--undoably-changed-buffers)
+ (when (buffer-live-p b)
+ (with-current-buffer b
+ (undo-auto--ensure-boundary cause))))
+ (setq undo-auto--undoably-changed-buffers nil))
+
+(defun undo-auto--boundary-timer ()
+ "Timer which will run `undo--auto-boundary-timer'."
+ (setq undo-auto--current-boundary-timer nil)
+ (undo-auto--boundaries 'timer))
+
+(defun undo-auto--boundary-ensure-timer ()
+ "Ensure that the `undo-auto-boundary-timer' is set."
+ (unless undo-auto--current-boundary-timer
+ (setq undo-auto--current-boundary-timer
+ (run-at-time 10 nil #'undo-auto--boundary-timer))))
+
+(defvar undo-auto--undoably-changed-buffers nil
+ "List of buffers that have changed recently.
+
+This list is maintained by `undo-auto--undoable-change' and
+`undo-auto--boundaries' and can be affected by changes to their
+default values.
+
+See also `undo-auto--buffer-undoably-changed'.")
+
+(defun undo-auto--add-boundary ()
+ "Add an `undo-boundary' in appropriate buffers."
+ (undo-auto--boundaries
+ (if undo-auto--this-command-amalgamating
+ 'amalgamate
+ 'command))
+ (setq undo-auto--this-command-amalgamating nil))
+
+(defun undo-auto--amalgamate ()
+ "Amalgamate undo if necessary.
+This function can be called after an amalgamating command. It
+removes the previous `undo-boundary' if a series of such calls
+have been made. By default `self-insert-command' and
+`delete-char' are the only amalgamating commands, although this
+function could be called by any command wishing to have this
+behaviour."
+ (let ((last-amalgamating-count
+ (undo-auto--last-boundary-amalgamating-number)))
+ (setq undo-auto--this-command-amalgamating t)
+ (when
+ last-amalgamating-count
+ (if
+ (and
+ (< last-amalgamating-count 20)
+ (eq this-command last-command))
+ ;; Amalgamate all buffers that have changed.
+ (dolist (b (cdr undo-auto--last-boundary-cause))
+ (when (buffer-live-p b)
+ (with-current-buffer
+ b
+ (when
+ ;; The head of `buffer-undo-list' is nil.
+ ;; `car-safe' doesn't work because
+ ;; `buffer-undo-list' need not be a list!
+ (and (listp buffer-undo-list)
+ (not (car buffer-undo-list)))
+ (setq buffer-undo-list
+ (cdr buffer-undo-list))))))
+ (setq undo-auto--last-boundary-cause 0)))))
+
+(defun undo-auto--undoable-change ()
+ "Called after every undoable buffer change."
+ (add-to-list 'undo-auto--undoably-changed-buffers (current-buffer))
+ (undo-auto--boundary-ensure-timer))
+;; End auto-boundary section
+
(defcustom undo-ask-before-discard nil
"If non-nil ask about discarding undo info for the current command.
Normally, Emacs discards the undo info for the current command if
;; but we don't want to ask the question again.
(setq undo-extra-outer-limit (+ size 50000))
(if (let (use-dialog-box track-mouse executing-kbd-macro )
- (yes-or-no-p (format "Buffer `%s' undo info is %d bytes long; discard it? "
- (buffer-name) size)))
+ (yes-or-no-p (format-message
+ "Buffer `%s' undo info is %d bytes long; discard it? "
+ (buffer-name) size)))
(progn (setq buffer-undo-list nil)
(setq undo-extra-outer-limit nil)
t)
nil))
(display-warning '(undo discard-info)
(concat
- (format "Buffer `%s' undo info was %d bytes long.\n"
- (buffer-name) size)
+ (format-message
+ "Buffer `%s' undo info was %d bytes long.\n"
+ (buffer-name) size)
"The undo info was discarded because it exceeded \
`undo-outer-limit'.
(buf-label (if (buffer-live-p buf)
`(,(buffer-name buf)
face link
- help-echo ,(concat "Visit buffer `"
- (buffer-name buf) "'")
+ help-echo ,(format-message
+ "Visit buffer `%s'"
+ (buffer-name buf))
follow-link t
process-buffer ,buf
action process-menu-visit-buffer)
(display-buffer buffer)
nil)
\f
+;;;; Prefix commands
+
+(setq prefix-command--needs-update nil)
+(setq prefix-command--last-echo nil)
+
+(defun internal-echo-keystrokes-prefix ()
+ ;; BEWARE: Called directly from the C code.
+ (if (not prefix-command--needs-update)
+ prefix-command--last-echo
+ (setq prefix-command--last-echo
+ (let ((strs nil))
+ (run-hook-wrapped 'prefix-command-echo-keystrokes-functions
+ (lambda (fun) (push (funcall fun) strs)))
+ (setq strs (delq nil strs))
+ (when strs (mapconcat #'identity strs " "))))))
+
+(defvar prefix-command-echo-keystrokes-functions nil
+ "Abnormal hook which constructs the description of the current prefix state.
+Each function is called with no argument, should return a string or nil.")
+
+(defun prefix-command-update ()
+ "Update state of prefix commands.
+Call it whenever you change the \"prefix command state\"."
+ (setq prefix-command--needs-update t))
+
+(defvar prefix-command-preserve-state-hook nil
+ "Normal hook run when a command needs to preserve the prefix.")
+
+(defun prefix-command-preserve-state ()
+ "Pass the current prefix command state to the next command.
+Should be called by all prefix commands.
+Runs `prefix-command-preserve-state-hook'."
+ (run-hooks 'prefix-command-preserve-state-hook)
+ ;; If the current command is a prefix command, we don't want the next (real)
+ ;; command to have `last-command' set to, say, `universal-argument'.
+ (setq this-command last-command)
+ (setq real-this-command real-last-command)
+ (prefix-command-update))
+
+(defun reset-this-command-lengths ()
+ (declare (obsolete prefix-command-preserve-state "25.1"))
+ nil)
+
+;;;;; The main prefix command.
+
+;; FIXME: Declaration of `prefix-arg' should be moved here!?
+
+(add-hook 'prefix-command-echo-keystrokes-functions
+ #'universal-argument--description)
+(defun universal-argument--description ()
+ (when prefix-arg
+ (concat "C-u"
+ (pcase prefix-arg
+ (`(-) " -")
+ (`(,(and (pred integerp) n))
+ (let ((str ""))
+ (while (and (> n 4) (= (mod n 4) 0))
+ (setq str (concat str " C-u"))
+ (setq n (/ n 4)))
+ (if (= n 4) str (format " %s" prefix-arg))))
+ (_ (format " %s" prefix-arg))))))
+
+(add-hook 'prefix-command-preserve-state-hook
+ #'universal-argument--preserve)
+(defun universal-argument--preserve ()
+ (setq prefix-arg current-prefix-arg))
+
(defvar universal-argument-map
(let ((map (make-sparse-keymap))
(universal-argument-minus
"Keymap used while processing \\[universal-argument].")
(defun universal-argument--mode ()
- (set-transient-map universal-argument-map))
+ (prefix-command-update)
+ (set-transient-map universal-argument-map nil))
(defun universal-argument ()
"Begin a numeric argument for the following command.
which is different in effect from any particular numeric argument.
These commands include \\[set-mark-command] and \\[start-kbd-macro]."
(interactive)
+ (prefix-command-preserve-state)
(setq prefix-arg (list 4))
(universal-argument--mode))
;; A subsequent C-u means to multiply the factor by 4 if we've typed
;; nothing but C-u's; otherwise it means to terminate the prefix arg.
(interactive "P")
+ (prefix-command-preserve-state)
(setq prefix-arg (if (consp arg)
(list (* 4 (car arg)))
(if (eq arg '-)
"Begin a negative numeric argument for the next command.
\\[universal-argument] following digits or minus sign ends the argument."
(interactive "P")
+ (prefix-command-preserve-state)
(setq prefix-arg (cond ((integerp arg) (- arg))
((eq arg '-) nil)
(t '-)))
"Part of the numeric argument for the next command.
\\[universal-argument] following digits or minus sign ends the argument."
(interactive "P")
+ (prefix-command-preserve-state)
(let* ((char (if (integerp last-command-event)
last-command-event
(get last-command-event 'ascii-character)))
(defcustom blink-matching-paren t
"Non-nil means show matching open-paren when close-paren is inserted.
-If t, highlight the paren. If `jump', move cursor to its position."
+If t, highlight the paren. If `jump', briefly move cursor to its
+position. If `jump-offscreen', move cursor there even if the
+position is off screen. With any other non-nil value, the
+off-screen position of the opening paren will be shown in the
+echo area."
:type '(choice
(const :tag "Disable" nil)
(const :tag "Highlight" t)
- (const :tag "Move cursor" jump))
+ (const :tag "Move cursor" jump)
+ (const :tag "Move cursor, even if off screen" jump-offscreen))
:group 'paren-blinking)
(defcustom blink-matching-paren-on-screen t
"Non-nil means show matching open-paren when it is on screen.
If nil, don't show it (but the open-paren can still be shown
-when it is off screen).
+in the echo area when it is off screen).
This variable has no effect if `blink-matching-paren' is nil.
\(In that case, the open-paren is never shown.)
(minibuffer-message "No matching parenthesis found")
(message "No matching parenthesis found"))))
((not blinkpos) nil)
- ((pos-visible-in-window-p blinkpos)
+ ((or
+ (eq blink-matching-paren 'jump-offscreen)
+ (pos-visible-in-window-p blinkpos))
;; 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)
- (if (eq blink-matching-paren 'jump)
+ (if (memq blink-matching-paren '(jump jump-offscreen))
(save-excursion
(goto-char blinkpos)
(sit-for blink-matching-delay))
(sit-for blink-matching-delay))
(delete-overlay blink-matching--overlay)))))
(t
- (save-excursion
- (let* ((orig-pos (prog1
- (point)
- (goto-char blinkpos)))
-
- (open-paren-line-string
+ (let ((open-paren-line-string
+ (save-excursion
+ (goto-char blinkpos)
;; Show what precedes the open in its line, if anything.
(cond
((save-excursion (skip-chars-backward " \t") (not (bolp)))
"..."
(buffer-substring blinkpos (1+ blinkpos))))
;; There is nothing to show except the char itself.
- (t (buffer-substring blinkpos (1+ blinkpos))))))
- ;; Because minibuffer-message causes a full redisplay, go back
- ;; to the original point before that happens.
- (goto-char orig-pos)
- (minibuffer-message
- "Matches %s"
- (substring-no-properties open-paren-line-string)))))))))
+ (t (buffer-substring blinkpos (1+ blinkpos)))))))
+ (minibuffer-message
+ "Matches %s"
+ (substring-no-properties open-paren-line-string))))))))
(defvar blink-paren-function 'blink-matching-open
"Function called, if non-nil, whenever a close parenthesis is inserted.
(push var warn-vars)))
(when warn-vars
(display-warning 'mail
- (format "\
+ (format-message "\
The default mail mode is now Message mode.
You have the following Mail mode variable%s customized:
\n %s\n\nTo use Mail mode, set `mail-user-agent' to sendmail-user-agent.
(when completion-show-help
(goto-char (point-min))
(if (display-mouse-p)
- (insert (substitute-command-keys
- "Click on a completion to select it.\n")))
+ (insert "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"))))))
(interactive "P")
(when (or arg (null ,varimp-sym))
(let ((val (completing-read
- ,(format "Select implementation for command `%s': "
- command-name)
+ ,(format-message
+ "Select implementation for command `%s': "
+ command-name)
,varalt-sym nil t)))
(unless (string-equal val "")
(when (null ,varimp-sym)
(message
- "Use `C-u M-x %s RET' to select another implementation"
+ "Use C-u M-x %s RET`to select another implementation"
,command-name)
(sit-for 3))
(customize-save-variable ',varimp-sym
(cdr (assoc-string val ,varalt-sym))))))
(if ,varimp-sym
(call-interactively ,varimp-sym)
- (message ,(format "No implementation selected for command `%s'"
- command-name)))))))
+ (message "%s" ,(format-message
+ "No implementation selected for command `%s'"
+ command-name)))))))
+
+\f
+;;; Functions for changing capitalization that Do What I Mean
+(defun upcase-dwim (arg)
+ "Upcase words in the region, if active; if not, upcase word at point.
+If the region is active, this function calls `upcase-region'.
+Otherwise, it calls `upcase-word', with prefix argument passed to it
+to upcase ARG words."
+ (interactive "*p")
+ (if (use-region-p)
+ (upcase-region (region-beginning) (region-end))
+ (upcase-word arg)))
+
+(defun downcase-dwim (arg)
+ "Downcase words in the region, if active; if not, downcase word at point.
+If the region is active, this function calls `downcase-region'.
+Otherwise, it calls `downcase-word', with prefix argument passed to it
+to downcase ARG words."
+ (interactive "*p")
+ (if (use-region-p)
+ (downcase-region (region-beginning) (region-end))
+ (downcase-word arg)))
+
+(defun capitalize-dwim (arg)
+ "Capitalize words in the region, if active; if not, capitalize word at point.
+If the region is active, this function calls `capitalize-region'.
+Otherwise, it calls `capitalize-word', with prefix argument passed to it
+to capitalize ARG words."
+ (interactive "*p")
+ (if (use-region-p)
+ (capitalize-region (region-beginning) (region-end))
+ (capitalize-word arg)))
\f