Merged from miles@gnu.org--gnu-2005 (patch 149-151, 629-641)
[bpt/emacs.git] / lisp / simple.el
index 40a2dae..15ff83e 100644 (file)
@@ -1,8 +1,7 @@
 ;;; simple.el --- basic editing commands for Emacs
 
 ;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-;;               2000, 2001, 2002, 2003, 2004, 2005
-;;        Free Software Foundation, Inc.
+;;   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: internal
@@ -35,6 +34,8 @@
   (autoload 'widget-convert "wid-edit")
   (autoload 'shell-mode "shell"))
 
+(defvar compilation-current-error)
+
 (defcustom idle-update-delay 0.5
   "*Idle time delay before updating various things on the screen.
 Various Emacs features that update auxiliary information when point moves
@@ -260,6 +261,14 @@ See variables `compilation-parse-errors-function' and
       (funcall next-error-function (prefix-numeric-value arg) reset)
       (run-hooks 'next-error-hook))))
 
+(defun next-error-internal ()
+  "Visit the source code corresponding to the `next-error' message at point."
+  (setq next-error-last-buffer (current-buffer))
+  ;; we know here that next-error-function is a valid symbol we can funcall
+  (with-current-buffer next-error-last-buffer
+    (funcall next-error-function 0 nil)
+    (run-hooks 'next-error-hook)))
+
 (defalias 'goto-next-locus 'next-error)
 (defalias 'next-match 'next-error)
 
@@ -309,11 +318,11 @@ select the source buffer."
 When turned on, cursor motion in the compilation, grep, occur or diff
 buffer causes automatic display of the corresponding source code
 location."
-  :group 'next-error :init-value " Fol"
+  :group 'next-error :init-value nil :lighter " Fol"
   (if (not next-error-follow-minor-mode)
       (remove-hook 'post-command-hook 'next-error-follow-mode-post-command-hook t)
     (add-hook 'post-command-hook 'next-error-follow-mode-post-command-hook nil t)
-    (make-variable-buffer-local 'next-error-follow-last-line)))
+    (make-local-variable 'next-error-follow-last-line)))
 
 ;;; Used as a `post-command-hook' by `next-error-follow-mode'
 ;;; for the *Compilation* *grep* and *Occur* buffers.
@@ -887,22 +896,42 @@ in *Help* buffer.  See also the command `describe-char'."
          (message "point=%d of %d (%d%%) column %d %s"
                   pos total percent col hscroll))
       (let ((coding buffer-file-coding-system)
-           encoded encoding-msg)
+           encoded encoding-msg display-prop under-display)
        (if (or (not coding)
                (eq (coding-system-type coding) t))
            (setq coding default-buffer-file-coding-system))
        (if (not (char-valid-p char))
            (setq encoding-msg
                  (format "(0%o, %d, 0x%x, invalid)" char char char))
-         (setq encoded (and (>= char 128) (encode-coding-char char coding)))
+         ;; Check if the character is displayed with some `display'
+         ;; text property.  In that case, set under-display to the
+         ;; buffer substring covered by that property.
+         (setq display-prop (get-text-property pos 'display))
+         (if display-prop
+             (let ((to (or (next-single-property-change pos 'display)
+                           (point-max))))
+               (if (< to (+ pos 4))
+                   (setq under-display "")
+                 (setq under-display "..."
+                       to (+ pos 4)))
+               (setq under-display
+                     (concat (buffer-substring-no-properties pos to)
+                             under-display)))
+           (setq encoded (and (>= char 128) (encode-coding-char char coding))))
          (setq encoding-msg
-               (if encoded
-                   (format "(0%o, %d, 0x%x, file %s)"
-                           char char char
-                           (if (> (length encoded) 1)
-                               "..."
-                             (encoded-string-description encoded coding)))
-                 (format "(0%o, %d, 0x%x)" char char char))))
+               (if display-prop
+                   (if (not (stringp display-prop))
+                       (format "(0%o, %d, 0x%x, part of display \"%s\")"
+                               char char char under-display)
+                     (format "(0%o, %d, 0x%x, part of display \"%s\"->\"%s\")"
+                             char char char under-display display-prop))
+                 (if encoded
+                     (format "(0%o, %d, 0x%x, file %s)"
+                             char char char
+                             (if (> (length encoded) 1)
+                                 "..."
+                               (encoded-string-description encoded coding)))
+                   (format "(0%o, %d, 0x%x)" char char char)))))
        (if detail
            ;; We show the detailed information about CHAR.
            (describe-char (point)))
@@ -913,9 +942,11 @@ in *Help* buffer.  See also the command `describe-char'."
                       (buffer-substring-no-properties (point) (1+ (point))))
                     encoding-msg pos total percent beg end col hscroll)
          (message "Char: %s %s point=%d of %d (%d%%) column %d %s"
-                  (if (< char 256)
-                      (single-key-description char)
-                    (buffer-substring-no-properties (point) (1+ (point))))
+                  (if enable-multibyte-characters
+                      (if (< char 128)
+                          (single-key-description char)
+                        (buffer-substring-no-properties (point) (1+ (point))))
+                    (single-key-description char))
                   encoding-msg pos total percent col hscroll))))))
 \f
 (defvar read-expression-map
@@ -962,8 +993,8 @@ display the result of expression evaluation."
                      (memq this-command '(eval-last-sexp eval-print-last-sexp)))
                  (prin1-char value))))
         (if char-string
-            (format " (0%o, 0x%x) = %s" value value char-string)
-          (format " (0%o, 0x%x)" value value)))))
+            (format " (#o%o, #x%x, %s)" value value char-string)
+          (format " (#o%o, #x%x)" value value)))))
 
 ;; We define this, rather than making `eval' interactive,
 ;; for the sake of completion of names like eval-region, eval-current-buffer.
@@ -1313,7 +1344,8 @@ as an argument limits undo to changes within the current region."
   ;; and will get another error.  To begin undoing the undos,
   ;; you must type some other command.
   (let ((modified (buffer-modified-p))
-       (recent-save (recent-auto-save-p)))
+       (recent-save (recent-auto-save-p))
+       message)
     ;; If we get an error in undo-start,
     ;; the next command should not be a "consecutive undo".
     ;; So set `this-command' to something other than `undo'.
@@ -1342,9 +1374,9 @@ as an argument limits undo to changes within the current region."
     ;; so, ask the user whether she wants to skip the redo/undo pair.
     (let ((equiv (gethash pending-undo-list undo-equiv-table)))
       (or (eq (selected-window) (minibuffer-window))
-         (message (if undo-in-region
-                      (if equiv "Redo in region!" "Undo in region!")
-                    (if equiv "Redo!" "Undo!"))))
+         (setq message (if undo-in-region
+                           (if equiv "Redo in region!" "Undo in region!")
+                         (if equiv "Redo!" "Undo!"))))
       (when (and (consp equiv) undo-no-redo)
        ;; The equiv entry might point to another redo record if we have done
        ;; undo-redo-undo-redo-... so skip to the very last equiv.
@@ -1386,7 +1418,10 @@ as an argument limits undo to changes within the current region."
     ;; Record what the current undo list says,
     ;; so the next command can tell if the buffer was modified in between.
     (and modified (not (buffer-modified-p))
-        (delete-auto-save-file-if-necessary recent-save))))
+        (delete-auto-save-file-if-necessary recent-save))
+    ;; Display a message announcing success.
+    (if message
+       (message message))))
 
 (defun buffer-disable-undo (&optional buffer)
   "Make BUFFER stop keeping undo information.
@@ -2288,6 +2323,8 @@ the text which should be made available.
 The second, optional, argument PUSH, has the same meaning as the
 similar argument to `x-set-cut-buffer', which see.")
 
+(make-variable-frame-local 'interprogram-cut-function)
+
 (defvar interprogram-paste-function nil
   "Function to call to get text cut from other programs.
 
@@ -2308,6 +2345,8 @@ most recent string, the function should return nil.  If it is
 difficult to tell whether Emacs or some other program provided the
 current string, it is probably good enough to return nil if the string
 is equal (according to `string=') to the last text Emacs provided.")
+
+(make-variable-frame-local 'interprogram-paste-function)
 \f
 
 
@@ -2358,7 +2397,7 @@ argument should still be a \"useful\" string for such uses."
       (menu-bar-update-yank-menu string (and replace (car kill-ring))))
   (if (and replace kill-ring)
       (setcar kill-ring string)
-    (setq kill-ring (cons string kill-ring))
+    (push string kill-ring)
     (if (> (length kill-ring) kill-ring-max)
        (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
   (setq kill-ring-yank-pointer kill-ring)
@@ -2968,8 +3007,7 @@ BUFFER (or buffer name), START and END.
 START and END specify the portion of the current buffer to be copied."
   (interactive "BCopy to buffer: \nr")
   (let ((oldbuf (current-buffer)))
-    (save-excursion
-      (set-buffer (get-buffer-create buffer))
+    (with-current-buffer (get-buffer-create buffer)
       (barf-if-buffer-read-only)
       (erase-buffer)
       (save-excursion
@@ -3081,6 +3119,13 @@ Display `Mark set' unless the optional second arg NOMSG is non-nil."
       (unless nomsg
        (message "Mark activated")))))
 
+(defcustom set-mark-command-repeat-pop nil
+  "*Non-nil means that repeating \\[set-mark-command] after popping will pop.
+This means that if you type C-u \\[set-mark-command] \\[set-mark-command]
+will pop twice."
+  :type 'boolean
+  :group 'editing)
+
 (defun set-mark-command (arg)
   "Set mark at where point is, or jump to mark.
 With no prefix argument, set mark, and push old mark position on local
@@ -3113,10 +3158,13 @@ purposes.  See the documentation of `set-mark' for more information."
     (if arg
        (pop-to-mark-command)
       (push-mark-command t)))
-   ((eq last-command 'pop-to-mark-command)
+   ((and set-mark-command-repeat-pop
+        (eq last-command 'pop-to-mark-command))
     (setq this-command 'pop-to-mark-command)
     (pop-to-mark-command))
-   ((and (eq last-command 'pop-global-mark) (not arg))
+   ((and set-mark-command-repeat-pop
+        (eq last-command 'pop-global-mark)
+        (not arg))
     (setq this-command 'pop-global-mark)
     (pop-global-mark))
    (arg
@@ -3241,8 +3289,8 @@ as a fallback, and won't change the buffer bounds.")
     (or (and (>= position (point-min))
             (<= position (point-max)))
        (if widen-automatically
-           (error "Global mark position is outside accessible part of buffer")
-         (widen)))
+           (widen)
+         (error "Global mark position is outside accessible part of buffer")))
     (goto-char position)
     (switch-to-buffer buffer)))
 \f
@@ -3510,10 +3558,11 @@ Outline mode sets this."
             ;; Compute the end of the line
             ;; ignoring effectively invisible newlines.
             (save-excursion
-              (end-of-line)
+              ;; Like end-of-line but ignores fields.
+              (skip-chars-forward "^\n")
               (while (and (not (eobp)) (line-move-invisible-p (point)))
                 (goto-char (next-char-property-change (point)))
-                (end-of-line))
+                (skip-chars-forward "^\n"))
               (point))))
 
        ;; Move to the desired column.
@@ -3667,9 +3716,18 @@ The goal column is stored in the variable `goal-column'."
         (setq goal-column nil)
         (message "No goal column"))
     (setq goal-column (current-column))
-    (message (substitute-command-keys
-             "Goal column %d (use \\[set-goal-column] with an arg to unset it)")
-            goal-column))
+    ;; The older method below can be erroneous if `set-goal-column' is bound
+    ;; to a sequence containing %
+    ;;(message (substitute-command-keys
+    ;;"Goal column %d (use \\[set-goal-column] with an arg to unset it)")
+    ;;goal-column)
+    (message "%s"
+            (concat 
+             (format "Goal column %d " goal-column)
+             (substitute-command-keys
+              "(use \\[set-goal-column] with an arg to unset it)")))
+    
+    )
   nil)
 \f
 
@@ -4208,8 +4266,9 @@ when it is off screen)."
   :group 'paren-blinking)
 
 (defcustom blink-matching-paren-distance (* 25 1024)
-  "*If non-nil, is maximum distance to search for matching open-paren."
-  :type 'integer
+  "*If non-nil, maximum distance to search backwards for matching open-paren.
+If nil, search stops at the beginning of the accessible portion of the buffer."
+  :type '(choice (const nil) integer)
   :group 'paren-blinking)
 
 (defcustom blink-matching-delay 1
@@ -4225,88 +4284,90 @@ when it is off screen)."
 (defun blink-matching-open ()
   "Move cursor momentarily to the beginning of the sexp before point."
   (interactive)
-  (and (> (point) (1+ (point-min)))
-       blink-matching-paren
-       ;; Verify an even number of quoting characters precede the close.
-       (= 1 (logand 1 (- (point)
-                        (save-excursion
-                          (forward-char -1)
-                          (skip-syntax-backward "/\\")
-                          (point)))))
-       (let* ((oldpos (point))
-             (blinkpos)
-             (mismatch)
-             matching-paren)
-        (save-excursion
-          (save-restriction
-            (if blink-matching-paren-distance
-                (narrow-to-region (max (point-min)
-                                       (- (point) blink-matching-paren-distance))
-                                  oldpos))
-            (condition-case ()
-                (let ((parse-sexp-ignore-comments
-                       (and parse-sexp-ignore-comments
-                            (not blink-matching-paren-dont-ignore-comments))))
-                  (setq blinkpos (scan-sexps oldpos -1)))
-              (error nil)))
-          (and blinkpos
-                ;; Not syntax '$'.
-               (not (eq (syntax-class (syntax-after blinkpos)) 8))
-               (setq matching-paren
-                     (let ((syntax (syntax-after blinkpos)))
-                       (and (consp syntax)
-                            (eq (syntax-class syntax) 4)
-                            (cdr syntax)))
-                     mismatch
-                     (or (null matching-paren)
-                         (/= (char-after (1- oldpos))
-                             matching-paren))))
-          (if mismatch (setq blinkpos nil))
-          (if blinkpos
-              ;; Don't log messages about paren matching.
-              (let (message-log-max)
-               (goto-char blinkpos)
-               (if (pos-visible-in-window-p)
-                   (and blink-matching-paren-on-screen
-                        (sit-for blink-matching-delay))
-                 (goto-char blinkpos)
-                 (message
-                  "Matches %s"
-                  ;; Show what precedes the open in its line, if anything.
-                  (if (save-excursion
-                        (skip-chars-backward " \t")
-                        (not (bolp)))
-                      (buffer-substring (progn (beginning-of-line) (point))
-                                        (1+ blinkpos))
-                    ;; Show what follows the open in its line, if anything.
-                    (if (save-excursion
-                          (forward-char 1)
-                          (skip-chars-forward " \t")
-                          (not (eolp)))
-                        (buffer-substring blinkpos
-                                          (progn (end-of-line) (point)))
-                      ;; Otherwise show the previous nonblank line,
-                      ;; if there is one.
-                      (if (save-excursion
-                            (skip-chars-backward "\n \t")
-                            (not (bobp)))
-                          (concat
-                           (buffer-substring (progn
+  (when (and (> (point) (point-min))
+            blink-matching-paren
+            ;; Verify an even number of quoting characters precede the close.
+            (= 1 (logand 1 (- (point)
+                              (save-excursion
+                                (forward-char -1)
+                                (skip-syntax-backward "/\\")
+                                (point))))))
+    (let* ((oldpos (point))
+          blinkpos
+          message-log-max  ; Don't log messages about paren matching.
+          matching-paren
+          open-paren-line-string)
+      (save-excursion
+       (save-restriction
+         (if blink-matching-paren-distance
+             (narrow-to-region (max (point-min)
+                                    (- (point) blink-matching-paren-distance))
+                               oldpos))
+         (condition-case ()
+             (let ((parse-sexp-ignore-comments
+                    (and parse-sexp-ignore-comments
+                         (not blink-matching-paren-dont-ignore-comments))))
+               (setq blinkpos (scan-sexps oldpos -1)))
+           (error nil)))
+       (and blinkpos
+            ;; Not syntax '$'.
+            (not (eq (syntax-class (syntax-after blinkpos)) 8))
+            (setq matching-paren
+                  (let ((syntax (syntax-after blinkpos)))
+                    (and (consp syntax)
+                         (eq (syntax-class syntax) 4)
+                         (cdr syntax)))))
+       (cond
+        ((or (null matching-paren)
+             (/= (char-before oldpos)
+                 matching-paren))
+         (message "Mismatched parentheses"))
+        ((not blinkpos)
+         (if (not blink-matching-paren-distance)
+             (message "Unmatched parenthesis")))
+        ((pos-visible-in-window-p blinkpos)
+         ;; Matching open within window, temporarily move to blinkpos but only
+         ;; if `blink-matching-paren-on-screen' is non-nil.
+         (when blink-matching-paren-on-screen
+           (save-excursion
+             (goto-char blinkpos)
+             (sit-for blink-matching-delay))))
+        (t
+         (save-excursion
+           (goto-char blinkpos)
+           (setq open-paren-line-string
+                 ;; Show what precedes the open in its line, if anything.
+                 (if (save-excursion
+                       (skip-chars-backward " \t")
+                       (not (bolp)))
+                     (buffer-substring (line-beginning-position)
+                                       (1+ blinkpos))
+                   ;; Show what follows the open in its line, if anything.
+                   (if (save-excursion
+                         (forward-char 1)
+                         (skip-chars-forward " \t")
+                         (not (eolp)))
+                       (buffer-substring blinkpos
+                                         (line-end-position))
+                     ;; Otherwise show the previous nonblank line,
+                     ;; if there is one.
+                     (if (save-excursion
+                           (skip-chars-backward "\n \t")
+                           (not (bobp)))
+                         (concat
+                          (buffer-substring (progn
                                               (skip-chars-backward "\n \t")
-                                              (beginning-of-line)
-                                              (point))
-                                             (progn (end-of-line)
-                                                    (skip-chars-backward " \t")
-                                                    (point)))
-                           ;; Replace the newline and other whitespace with `...'.
-                           "..."
-                           (buffer-substring blinkpos (1+ blinkpos)))
-                        ;; There is nothing to show except the char itself.
-                        (buffer-substring blinkpos (1+ blinkpos))))))))
-            (cond (mismatch
-                   (message "Mismatched parentheses"))
-                  ((not blink-matching-paren-distance)
-                   (message "Unmatched parenthesis"))))))))
+                                              (line-beginning-position))
+                                            (progn (end-of-line)
+                                                   (skip-chars-backward " \t")
+                                                   (point)))
+                          ;; Replace the newline and other whitespace with `...'.
+                          "..."
+                          (buffer-substring blinkpos (1+ blinkpos)))
+                       ;; There is nothing to show except the char itself.
+                       (buffer-substring blinkpos (1+ blinkpos)))))))
+         (message "Matches %s"
+                  (substring-no-properties open-paren-line-string))))))))
 
 ;Turned off because it makes dbx bomb out.
 (setq blink-paren-function 'blink-matching-open)
@@ -4529,10 +4590,10 @@ in the definition is used to check that VALUE is valid.
 With a prefix argument, set VARIABLE to VALUE buffer-locally."
   (interactive
    (let* ((default-var (variable-at-point))
-          (var (if (symbolp default-var)
-                       (read-variable (format "Set variable (default %s): " default-var)
-                                      default-var)
-                     (read-variable "Set variable: ")))
+          (var (if (user-variable-p default-var)
+                  (read-variable (format "Set variable (default %s): " default-var)
+                                 default-var)
+                (read-variable "Set variable: ")))
          (minibuffer-help-form '(describe-variable var))
          (prop (get var 'variable-interactive))
           (obsolete (car (get var 'byte-obsolete-variable)))
@@ -4557,7 +4618,8 @@ With a prefix argument, set VARIABLE to VALUE buffer-locally."
                                             arg))
                    (read
                     (read-string prompt nil
-                                 'set-variable-value-history))))))
+                                 'set-variable-value-history
+                                (format "%S" (symbol-value var))))))))
      (list var val current-prefix-arg)))
 
   (and (custom-variable-p variable)
@@ -4801,10 +4863,13 @@ Called from `temp-buffer-show-hook'."
   "Normal hook run at the end of setting up a completion list buffer.
 When this hook is run, the current buffer is the one in which the
 command to display the completion list buffer was run.
-The completion list buffer is available as the value of `standard-output'.")
+The completion list buffer is available as the value of `standard-output'.
+The common prefix substring for completion may be available as the 
+value of `completion-common-substring'. See also `display-completion-list'.")
+
+
+;; Variables and faces used in `completion-setup-function'.
 
-;; This function goes in completion-setup-hook, so that it is called
-;; after the text of the completion list buffer is written.
 (defface completions-first-difference
   '((t (:inherit bold)))
   "Face put on the first uncommon character in completions in *Completions* buffer."
@@ -4824,9 +4889,21 @@ of the differing parts is, by contrast, slightly highlighted."
 (defvar completion-root-regexp "^/"
   "Regexp to use in `completion-setup-function' to find the root directory.")
 
+(defvar completion-common-substring nil
+  "Common prefix substring to use in `completion-setup-function' to put faces.
+The value is set by `display-completion-list' during running `completion-setup-hook'.
+
+To put faces, `completions-first-difference' and `completions-common-part' 
+into \"*Completions*\* buffer, the common prefix substring in completions is
+needed as a hint. (Minibuffer is a special case. The content of minibuffer itself 
+is the substring.)")
+
+;; This function goes in completion-setup-hook, so that it is called
+;; after the text of the completion list buffer is written.
 (defun completion-setup-function ()
-  (let ((mainbuf (current-buffer))
-       (mbuf-contents (minibuffer-contents)))
+  (let* ((mainbuf (current-buffer))
+         (mbuf-contents (minibuffer-contents))
+         (common-string-length (length mbuf-contents)))
     ;; When reading a file name in the minibuffer,
     ;; set default-directory in the minibuffer
     ;; so it will get copied into the completion list buffer.
@@ -4838,12 +4915,11 @@ of the differing parts is, by contrast, slightly highlighted."
     ;; FIXME: This still doesn't work if the text to be completed
     ;; starts with a `-'.
     (when (and partial-completion-mode (not (eobp)))
-      (setq mbuf-contents
-           (substring mbuf-contents 0 (- (point) (point-max)))))
+      (setq common-string-length
+            (- common-string-length (- (point) (point-max)))))
     (with-current-buffer standard-output
       (completion-list-mode)
-      (make-local-variable 'completion-reference-buffer)
-      (setq completion-reference-buffer mainbuf)
+      (set (make-local-variable 'completion-reference-buffer) mainbuf)
       (if minibuffer-completing-file-name
          ;; For file name completion,
          ;; use the number of chars before the start of the
@@ -4862,28 +4938,26 @@ of the differing parts is, by contrast, slightly highlighted."
                      (funcall (get minibuffer-completion-table 'completion-base-size-function)))
              (setq completion-base-size 0))))
       ;; Put faces on first uncommon characters and common parts.
-      (when completion-base-size
-       (let* ((common-string-length
-               (- (length mbuf-contents) completion-base-size))
-              (element-start (next-single-property-change
-                              (point-min)
-                              'mouse-face))
-              (element-common-end
-               (and element-start
-                    (+ (or element-start nil) common-string-length)))
-              (maxp (point-max)))
-         (while (and element-start (< element-common-end maxp))
+      (when (or completion-common-substring completion-base-size)
+        (setq common-string-length
+               (if completion-common-substring
+                   (length completion-common-substring)
+                  (- common-string-length completion-base-size)))
+       (let ((element-start (point-min))
+              (maxp (point-max))
+              element-common-end)
+         (while (and (setq element-start
+                            (next-single-property-change
+                             element-start 'mouse-face))
+                      (< (setq element-common-end
+                               (+ element-start common-string-length))
+                         maxp))
            (when (and (get-char-property element-start 'mouse-face)
                       (get-char-property element-common-end 'mouse-face))
              (put-text-property element-start element-common-end
                                 'font-lock-face 'completions-common-part)
              (put-text-property element-common-end (1+ element-common-end)
-                                'font-lock-face 'completions-first-difference))
-           (setq element-start (next-single-property-change
-                                element-start
-                                'mouse-face))
-           (if element-start
-               (setq element-common-end  (+ element-start common-string-length))))))
+                                'font-lock-face 'completions-first-difference)))))
       ;; Insert help string.
       (goto-char (point-min))
       (if (display-mouse-p)
@@ -4895,14 +4969,8 @@ select the completion near point.\n\n")))))
 
 (add-hook 'completion-setup-hook 'completion-setup-function)
 
-(define-key minibuffer-local-completion-map [prior]
-  'switch-to-completions)
-(define-key minibuffer-local-must-match-map [prior]
-  'switch-to-completions)
-(define-key minibuffer-local-completion-map "\M-v"
-  'switch-to-completions)
-(define-key minibuffer-local-must-match-map "\M-v"
-  'switch-to-completions)
+(define-key minibuffer-local-completion-map [prior] 'switch-to-completions)
+(define-key minibuffer-local-completion-map "\M-v"  'switch-to-completions)
 
 (defun switch-to-completions ()
   "Select the completion list window."
@@ -5174,36 +5242,33 @@ the front of the list of recently selected ones."
 \f
 ;;; Handling of Backspace and Delete keys.
 
-(defcustom normal-erase-is-backspace
-  (and (not noninteractive)
-       (or (memq system-type '(ms-dos windows-nt))
-          (eq window-system 'mac)
-          (and (memq window-system '(x))
-               (fboundp 'x-backspace-delete-keys-p)
-               (x-backspace-delete-keys-p))
-          ;; If the terminal Emacs is running on has erase char
-          ;; set to ^H, use the Backspace key for deleting
-          ;; backward and, and the Delete key for deleting forward.
-          (and (null window-system)
-               (eq tty-erase-char ?\^H))))
-  "If non-nil, Delete key deletes forward and Backspace key deletes backward.
-
-On window systems, the default value of this option is chosen
-according to the keyboard used.  If the keyboard has both a Backspace
-key and a Delete key, and both are mapped to their usual meanings, the
-option's default value is set to t, so that Backspace can be used to
-delete backward, and Delete can be used to delete forward.
-
-If not running under a window system, customizing this option accomplishes
-a similar effect by mapping C-h, which is usually generated by the
-Backspace key, to DEL, and by mapping DEL to C-d via
-`keyboard-translate'.  The former functionality of C-h is available on
-the F1 key.  You should probably not use this setting if you don't
-have both Backspace, Delete and F1 keys.
+(defcustom normal-erase-is-backspace 'maybe
+  "Set the default behaviour of the Delete and Backspace keys.
+
+If set to t, Delete key deletes forward and Backspace key deletes
+backward.
+
+If set to nil, both Delete and Backspace keys delete backward.
+
+If set to 'maybe (which is the default), Emacs automatically
+selects a behaviour.  On window systems, the behaviour depends on
+the keyboard used.  If the keyboard has both a Backspace key and
+a Delete key, and both are mapped to their usual meanings, the
+option's default value is set to t, so that Backspace can be used
+to delete backward, and Delete can be used to delete forward.
+
+If not running under a window system, customizing this option
+accomplishes a similar effect by mapping C-h, which is usually
+generated by the Backspace key, to DEL, and by mapping DEL to C-d
+via `keyboard-translate'.  The former functionality of C-h is
+available on the F1 key.  You should probably not use this
+setting if you don't have both Backspace, Delete and F1 keys.
 
 Setting this variable with setq doesn't take effect.  Programmatically,
 call `normal-erase-is-backspace-mode' (which see) instead."
-  :type 'boolean
+  :type '(choice (const :tag "Off" nil)
+                (const :tag "Maybe" maybe)
+                (other :tag "On" t))
   :group 'editing-basics
   :version "21.1"
   :set (lambda (symbol value)
@@ -5213,17 +5278,40 @@ call `normal-erase-is-backspace-mode' (which see) instead."
             (normal-erase-is-backspace-mode (or value 0))
           (set-default symbol value))))
 
+(defun normal-erase-is-backspace-setup-frame (&optional frame)
+  "Set up `normal-erase-is-backspace-mode' on FRAME, if necessary."
+  (unless frame (setq frame (selected-frame)))
+  (with-selected-frame frame
+    (unless (terminal-parameter-p nil 'normal-erase-is-backspace)
+      (if (cond ((terminal-parameter-p nil 'normal-erase-is-backspace)
+                (terminal-parameter nil 'normal-erase-is-backspace))
+               ((eq normal-erase-is-backspace 'maybe)
+                (and (not noninteractive)
+                     (or (memq system-type '(ms-dos windows-nt))
+                         (eq window-system 'mac)
+                         (and (memq window-system '(x))
+                              (fboundp 'x-backspace-delete-keys-p)
+                              (x-backspace-delete-keys-p))
+                         ;; If the terminal Emacs is running on has erase char
+                         ;; set to ^H, use the Backspace key for deleting
+                         ;; backward and, and the Delete key for deleting forward.
+                         (and (null window-system)
+                              (eq tty-erase-char ?\^H)))))
+               (t
+                normal-erase-is-backspace))
+         (normal-erase-is-backspace-mode 1)
+       (normal-erase-is-backspace-mode 0)))))
 
 (defun normal-erase-is-backspace-mode (&optional arg)
   "Toggle the Erase and Delete mode of the Backspace and Delete keys.
 
 With numeric arg, turn the mode on if and only if ARG is positive.
 
-On window systems, when this mode is on, Delete is mapped to C-d and
-Backspace is mapped to DEL; when this mode is off, both Delete and
-Backspace are mapped to DEL.  (The remapping goes via
-`function-key-map', so binding Delete or Backspace in the global or
-local keymap will override that.)
+On window systems, when this mode is on, Delete is mapped to C-d
+and Backspace is mapped to DEL; when this mode is off, both
+Delete and Backspace are mapped to DEL.  (The remapping goes via
+`local-function-key-map', so binding Delete or Backspace in the
+global or local keymap will override that.)
 
 In addition, on window systems, the bindings of C-Delete, M-Delete,
 C-M-Delete, C-Backspace, M-Backspace, and C-M-Backspace are changed in
@@ -5245,32 +5333,33 @@ have both Backspace, Delete and F1 keys.
 
 See also `normal-erase-is-backspace'."
   (interactive "P")
-  (setq normal-erase-is-backspace
-       (if arg
-           (> (prefix-numeric-value arg) 0)
-         (not normal-erase-is-backspace)))
+  (set-terminal-parameter
+   nil 'normal-erase-is-backspace
+   (if arg
+       (> (prefix-numeric-value arg) 0)
+     (not (terminal-parameter nil 'normal-erase-is-backspace))))
 
   (cond ((or (memq window-system '(x w32 mac pc))
             (memq system-type '(ms-dos windows-nt)))
-        (let ((bindings
-               `(([C-delete] [C-backspace])
-                 ([M-delete] [M-backspace])
-                 ([C-M-delete] [C-M-backspace])
-                 (,esc-map
-                  [C-delete] [C-backspace])))
-              (old-state (lookup-key function-key-map [delete])))
-
-          (if normal-erase-is-backspace
+        (let* ((bindings
+                `(([C-delete] [C-backspace])
+                  ([M-delete] [M-backspace])
+                  ([C-M-delete] [C-M-backspace])
+                  (,esc-map
+                   [C-delete] [C-backspace])))
+               (old-state (lookup-key local-function-key-map [delete])))
+
+          (if (terminal-parameter nil 'normal-erase-is-backspace)
               (progn
-                (define-key function-key-map [delete] [?\C-d])
-                (define-key function-key-map [kp-delete] [?\C-d])
-                (define-key function-key-map [backspace] [?\C-?]))
-            (define-key function-key-map [delete] [?\C-?])
-            (define-key function-key-map [kp-delete] [?\C-?])
-            (define-key function-key-map [backspace] [?\C-?]))
+                (define-key local-function-key-map [delete] [?\C-d])
+                (define-key local-function-key-map [kp-delete] [?\C-d])
+                (define-key local-function-key-map [backspace] [?\C-?]))
+            (define-key local-function-key-map [delete] [?\C-?])
+            (define-key local-function-key-map [kp-delete] [?\C-?])
+            (define-key local-function-key-map [backspace] [?\C-?]))
 
           ;; Maybe swap bindings of C-delete and C-backspace, etc.
-          (unless (equal old-state (lookup-key function-key-map [delete]))
+          (unless (equal old-state (lookup-key local-function-key-map [delete]))
             (dolist (binding bindings)
               (let ((map global-map))
                 (when (keymapp (car binding))
@@ -5282,7 +5371,7 @@ See also `normal-erase-is-backspace'."
                   (define-key map key1 binding2)
                   (define-key map key2 binding1)))))))
         (t
-         (if normal-erase-is-backspace
+         (if (terminal-parameter nil 'normal-erase-is-backspace)
              (progn
                (keyboard-translate ?\C-h ?\C-?)
                (keyboard-translate ?\C-? ?\C-d))