(rmail-forward-separator-regex): Fix typo in docstring.
[bpt/emacs.git] / lisp / simple.el
index f5bc8a4..ba661e5 100644 (file)
@@ -1,7 +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
+;;               2000, 2001, 2002, 2003, 2004, 2005
 ;;        Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
   (autoload 'widget-convert "wid-edit")
   (autoload 'shell-mode "shell"))
 
+(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
+wait this many seconds after Emacs becomes idle before doing an update."
+  :type 'number
+  :group 'display
+  :version "22.1")
 
 (defgroup killing nil
   "Killing and yanking commands."
@@ -44,8 +51,6 @@
   "Highlight (un)matching of parens and expressions."
   :group 'matching)
 
-(define-key global-map [?\C-x right] 'next-buffer)
-(define-key global-map [?\C-x left] 'prev-buffer)
 (defun next-buffer ()
   "Switch to the next buffer in cyclic order."
   (interactive)
 (defgroup next-error nil
   "next-error support framework."
   :group 'compilation
-  :version "21.4")
+  :version "22.1")
 
 (defface next-error
   '((t (:inherit region)))
   "Face used to highlight next error locus."
   :group 'next-error
-  :version "21.4")
+  :version "22.1")
 
 (defcustom next-error-highlight 0.1
   "*Highlighting of locations in selected source buffers.
@@ -90,7 +95,7 @@ If `fringe-arrow', indicate the locus by the fringe arrow."
                  (const :tag "No highlighting" nil)
                  (const :tag "Fringe arrow" 'fringe-arrow))
   :group 'next-error
-  :version "21.4")
+  :version "22.1")
 
 (defcustom next-error-highlight-no-select 0.1
   "*Highlighting of locations in non-selected source buffers.
@@ -103,7 +108,13 @@ If `fringe-arrow', indicate the locus by the fringe arrow."
                  (const :tag "No highlighting" nil)
                  (const :tag "Fringe arrow" 'fringe-arrow))
   :group 'next-error
-  :version "21.4")
+  :version "22.1")
+
+(defvar next-error-highlight-timer nil)
+
+(defvar next-error-overlay-arrow-position nil)
+(put 'next-error-overlay-arrow-position 'overlay-arrow-string "=>")
+(add-to-list 'overlay-arrow-variable-list 'next-error-overlay-arrow-position)
 
 (defvar next-error-last-buffer nil
   "The most recent next-error buffer.
@@ -245,8 +256,6 @@ See variables `compilation-parse-errors-function' and
 (defalias 'goto-next-locus 'next-error)
 (defalias 'next-match 'next-error)
 
-(define-key ctl-x-map "`" 'next-error)
-
 (defun previous-error (&optional n)
   "Visit previous next-error message and corresponding source code.
 
@@ -293,7 +302,7 @@ 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."
-  nil " Fol" nil
+  :group 'next-error :init-value " 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)
@@ -647,15 +656,16 @@ If BACKWARD-ONLY is non-nil, only delete spaces before point."
        (skip-chars-backward " \t")
        (constrain-to-field nil orig-pos)))))
 
-(defun just-one-space ()
-  "Delete all spaces and tabs around point, leaving one space."
-  (interactive "*")
+(defun just-one-space (&optional n)
+  "Delete all spaces and tabs around point, leaving one space (or N spaces)."
+  (interactive "*p")
   (let ((orig-pos (point)))
     (skip-chars-backward " \t")
     (constrain-to-field nil orig-pos)
-    (if (= (following-char) ? )
-       (forward-char 1)
-      (insert ? ))
+    (dotimes (i (or n 1))
+      (if (= (following-char) ?\ )
+         (forward-char 1)
+       (insert ?\ )))
     (delete-region
      (point)
      (progn
@@ -732,10 +742,49 @@ that uses or sets the mark."
 
 ;; Counting lines, one way or another.
 
-(defun goto-line (arg)
-  "Goto line ARG, counting from line 1 at beginning of buffer."
-  (interactive "NGoto line: ")
-  (setq arg (prefix-numeric-value arg))
+(defun goto-line (arg &optional buffer)
+  "Goto line ARG, counting from line 1 at beginning of buffer.
+Normally, move point in the current buffer.
+With just \\[universal-argument] as argument, move point in the most recently
+displayed other buffer, and switch to it.  When called from Lisp code,
+the optional argument BUFFER specifies a buffer to switch to.
+
+If there's a number in the buffer at point, it is the default for ARG."
+  (interactive
+   (if (and current-prefix-arg (not (consp current-prefix-arg)))
+       (list (prefix-numeric-value current-prefix-arg))
+     ;; Look for a default, a number in the buffer at point.
+     (let* ((default
+             (save-excursion
+               (skip-chars-backward "0-9")
+               (if (looking-at "[0-9]")
+                   (buffer-substring-no-properties
+                    (point)
+                    (progn (skip-chars-forward "0-9")
+                           (point))))))
+           ;; Decide if we're switching buffers.
+           (buffer
+            (if (consp current-prefix-arg)
+                (other-buffer (current-buffer) t)))
+           (buffer-prompt
+            (if buffer
+                (concat " in " (buffer-name buffer))
+              "")))
+       ;; Read the argument, offering that number (if any) as default.
+       (list (read-from-minibuffer (format (if default "Goto line%s (%s): "
+                                            "Goto line%s: ")
+                                          buffer-prompt
+                                          default)
+                                  nil nil t
+                                  'minibuffer-history
+                                  default)
+            buffer))))
+  ;; Switch to the desired buffer, one way or another.
+  (if buffer
+      (let ((window (get-buffer-window buffer)))
+       (if window (select-window window)
+         (switch-to-buffer-other-window buffer))))
+  ;; Move to the specified line number in that buffer.
   (save-restriction
     (widen)
     (goto-char 1)
@@ -871,21 +920,21 @@ in *Help* buffer.  See also the command `describe-char'."
 (defvar read-expression-history nil)
 
 (defcustom eval-expression-print-level 4
-  "*Value to use for `print-level' when printing value in `eval-expression'.
+  "Value for `print-level' while printing value in `eval-expression'.
 A value of nil means no limit."
   :group 'lisp
   :type '(choice (const :tag "No Limit" nil) integer)
   :version "21.1")
 
 (defcustom eval-expression-print-length 12
-  "*Value to use for `print-length' when printing value in `eval-expression'.
+  "Value for `print-length' while printing value in `eval-expression'.
 A value of nil means no limit."
   :group 'lisp
   :type '(choice (const :tag "No Limit" nil) integer)
   :version "21.1")
 
 (defcustom eval-expression-debug-on-error t
-  "*Non-nil means set `debug-on-error' when evaluating in `eval-expression'.
+  "If non-nil set `debug-on-error' to t in `eval-expression'.
 If nil, don't change the value of `debug-on-error'."
   :group 'lisp
   :type 'boolean
@@ -899,9 +948,9 @@ display the result of expression evaluation."
   (if (and (integerp value)
            (or (not (memq this-command '(eval-last-sexp eval-print-last-sexp)))
                (eq this-command last-command)
-               (and (boundp 'edebug-active) edebug-active)))
+               (if (boundp 'edebug-active) edebug-active)))
       (let ((char-string
-             (if (or (and (boundp 'edebug-active) edebug-active)
+             (if (or (if (boundp 'edebug-active) edebug-active)
                      (memq this-command '(eval-last-sexp eval-print-last-sexp)))
                  (prin1-char value))))
         (if char-string
@@ -1226,7 +1275,9 @@ Return 0 if current buffer is not a mini-buffer."
 (defalias 'advertised-undo 'undo)
 
 (defconst undo-equiv-table (make-hash-table :test 'eq :weakness t)
-  "Table mapping redo records to the corresponding undo one.")
+  "Table mapping redo records to the corresponding undo one.
+A redo record for undo-in-region maps to t.
+A redo record for ordinary undo maps to the following (earlier) undo.")
 
 (defvar undo-in-region nil
   "Non-nil if `pending-undo-list' is not just a tail of `buffer-undo-list'.")
@@ -1234,9 +1285,9 @@ Return 0 if current buffer is not a mini-buffer."
 (defvar undo-no-redo nil
   "If t, `undo' doesn't go through redo entries.")
 
-(defvar undo-list-saved nil
-  "The value of `buffer-undo-list' saved by the last undo command.")
-(make-variable-buffer-local 'undo-list-saved)
+(defvar pending-undo-list nil
+  "Within a run of consecutive undo commands, list remaining to be undone.
+t if we undid all the way to the end of it.")
 
 (defun undo (&optional arg)
   "Undo some previous changes.
@@ -1261,12 +1312,15 @@ as an argument limits undo to changes within the current region."
     (setq this-command 'undo-start)
 
     (unless (and (eq last-command 'undo)
-                ;; If something (a timer or filter?) changed the buffer
-                ;; since the previous command, don't continue the undo seq.
-                (let ((list buffer-undo-list))
-                  (while (eq (car list) nil)
-                    (setq list (cdr list)))
-                  (eq undo-list-saved list)))
+                (or (eq pending-undo-list t)
+                    ;; If something (a timer or filter?) changed the buffer
+                    ;; since the previous command, don't continue the undo seq.
+                    (let ((list buffer-undo-list))
+                      (while (eq (car list) nil)
+                        (setq list (cdr list)))
+                      ;; If the last undo record made was made by undo
+                      ;; it shows nothing else happened in between.
+                      (gethash list undo-equiv-table))))
       (setq undo-in-region
            (if transient-mark-mode mark-active (and arg (not (numberp arg)))))
       (if undo-in-region
@@ -1283,7 +1337,7 @@ as an argument limits undo to changes within the current region."
          (message (if undo-in-region
                       (if equiv "Redo in region!" "Undo in region!")
                     (if equiv "Redo!" "Undo!"))))
-      (when (and equiv undo-no-redo)
+      (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.
        (while (let ((next (gethash equiv undo-equiv-table)))
@@ -1294,10 +1348,13 @@ as an argument limits undo to changes within the current region."
         (prefix-numeric-value arg)
        1))
     ;; Record the fact that the just-generated undo records come from an
-    ;; undo operation, so we can skip them later on.
+    ;; undo operation--that is, they are redo records.
+    ;; In the ordinary case (not within a region), map the redo
+    ;; record to the following undos.
     ;; I don't know how to do that in the undo-in-region case.
-    (unless undo-in-region
-      (puthash buffer-undo-list pending-undo-list undo-equiv-table))
+    (puthash buffer-undo-list
+            (if undo-in-region 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.
     (let ((tail buffer-undo-list)
@@ -1320,7 +1377,6 @@ as an argument limits undo to changes within the current region."
        (setq prev tail tail (cdr tail))))
     ;; Record what the current undo list says,
     ;; so the next command can tell if the buffer was modified in between.
-    (setq undo-list-saved buffer-undo-list)
     (and modified (not (buffer-modified-p))
         (delete-auto-save-file-if-necessary recent-save))))
 
@@ -1329,8 +1385,7 @@ as an argument limits undo to changes within the current region."
 No argument or nil as argument means do this for the current buffer."
   (interactive)
   (with-current-buffer (if buffer (get-buffer buffer) (current-buffer))
-    (setq buffer-undo-list t
-         undo-list-saved nil)))
+    (setq buffer-undo-list t)))
 
 (defun undo-only (&optional arg)
   "Undo some previous changes.
@@ -1339,12 +1394,6 @@ A numeric argument serves as a repeat count.
 Contrary to `undo', this will not redo a previous undo."
   (interactive "*p")
   (let ((undo-no-redo t)) (undo arg)))
-;; Richard said that we should not use C-x <uppercase letter> and I have
-;; no idea whereas to bind it.  Any suggestion welcome.  -stef
-;; (define-key ctl-x-map "U" 'undo-only)
-
-(defvar pending-undo-list nil
-  "Within a run of consecutive undo commands, list remaining to be undone.")
 
 (defvar undo-in-progress nil
   "Non-nil while performing an undo.
@@ -1354,12 +1403,14 @@ Some change-hooks test this variable to do something different.")
   "Undo back N undo-boundaries beyond what was already undone recently.
 Call `undo-start' to get ready to undo recent changes,
 then call `undo-more' one or more times to undo them."
-  (or pending-undo-list
+  (or (listp pending-undo-list)
       (error (format "No further undo information%s"
                     (if (and transient-mark-mode mark-active)
                         " for region" ""))))
   (let ((undo-in-progress t))
-    (setq pending-undo-list (primitive-undo count pending-undo-list))))
+    (setq pending-undo-list (primitive-undo count pending-undo-list))
+    (if (null pending-undo-list)
+       (setq pending-undo-list t))))
 
 ;; Deep copy of a list
 (defun undo-copy-list (list)
@@ -1524,33 +1575,76 @@ is not *inside* the region START...END."
             '(0 . 0)))
     '(0 . 0)))
 
+(defcustom undo-ask-before-discard t
+  "If non-nil ask about discarding undo info for the current command.
+Normally, Emacs discards the undo info for the current command if
+it exceeds `undo-outer-limit'.  But if you set this option
+non-nil, it asks in the echo area whether to discard the info.
+If you answer no, there a slight risk that Emacs might crash, so
+only do it if you really want to undo the command.
+
+This option is mainly intended for debugging.  You have to be
+careful if you use it for other purposes.  Garbage collection is
+inhibited while the question is asked, meaning that Emacs might
+leak memory.  So you should make sure that you do not wait
+excessively long before answering the question."
+  :type 'boolean
+  :group 'undo
+  :version "22.1")
+
 (defvar undo-extra-outer-limit nil
   "If non-nil, an extra level of size that's ok in an undo item.
 We don't ask the user about truncating the undo list until the
-current item gets bigger than this amount.")
+current item gets bigger than this amount.
+
+This variable only matters if `undo-ask-before-discard' is non-nil.")
 (make-variable-buffer-local 'undo-extra-outer-limit)
 
-;; When the first undo batch in an undo list is longer than undo-outer-limit,
-;; this function gets called to ask the user what to do.
-;; Garbage collection is inhibited around the call,
-;; so it had better not do a lot of consing.
+;; When the first undo batch in an undo list is longer than
+;; undo-outer-limit, this function gets called to warn the user that
+;; the undo info for the current command was discarded.  Garbage
+;; collection is inhibited around the call, so it had better not do a
+;; lot of consing.
 (setq undo-outer-limit-function 'undo-outer-limit-truncate)
 (defun undo-outer-limit-truncate (size)
-  (when (or (null undo-extra-outer-limit)
-           (> size undo-extra-outer-limit))
-    ;; Don't ask the question again unless it gets even bigger.
-    ;; This applies, in particular, if the user quits from the question.
-    ;; Such a quit quits out of GC, but something else will call GC
-    ;; again momentarily.  It will call this function again,
-    ;; but we don't want to ask the question again.
-    (setq undo-extra-outer-limit (+ size 50000))
-    (if (let (use-dialog-box)
-         (yes-or-no-p (format "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)))
+  (if undo-ask-before-discard
+      (when (or (null undo-extra-outer-limit)
+               (> size undo-extra-outer-limit))
+       ;; Don't ask the question again unless it gets even bigger.
+       ;; This applies, in particular, if the user quits from the question.
+       ;; Such a quit quits out of GC, but something else will call GC
+       ;; again momentarily.  It will call this function again,
+       ;; 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)))
+           (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)
+                     "The undo info was discarded because it exceeded \
+`undo-outer-limit'.
+
+This is normal if you executed a command that made a huge change
+to the buffer.  In that case, to prevent similar problems in the
+future, set `undo-outer-limit' to a value that is large enough to
+cover the maximum size of normal changes you expect a single
+command to make, but not so large that it might exceed the
+maximum memory allotted to Emacs.
+
+If you did not execute any such command, the situation is
+probably due to a bug and you should report it.
+
+You can disable the popping up of this buffer by adding the entry
+\(undo discard-info) to the user option `warning-suppress-types'.\n")
+                    :warning)
+    (setq buffer-undo-list nil)
+    t))
 \f
 (defvar shell-command-history nil
   "History list for some commands that read shell commands.")
@@ -2133,6 +2227,42 @@ These commands include \\[set-mark-command] and \\[start-kbd-macro]."
   (reset-this-command-lengths)
   (restore-overriding-map))
 \f
+(defvar buffer-substring-filters nil
+  "List of filter functions for `filter-buffer-substring'.
+Each function must accept a single argument, a string, and return
+a string.  The buffer substring is passed to the first function
+in the list, and the return value of each function is passed to
+the next.  The return value of the last function is used as the
+return value of `filter-buffer-substring'.
+
+If this variable is nil, no filtering is performed.")
+
+(defun filter-buffer-substring (beg end &optional delete)
+  "Return the buffer substring between BEG and END, after filtering.
+The buffer substring is passed through each of the filter
+functions in `buffer-substring-filters', and the value from the
+last filter function is returned.  If `buffer-substring-filters'
+is nil, the buffer substring is returned unaltered.
+
+If DELETE is non-nil, the text between BEG and END is deleted
+from the buffer.
+
+Point is temporarily set to BEG before calling
+`buffer-substring-filters', in case the functions need to know
+where the text came from.
+
+This function should be used instead of `buffer-substring' or
+`delete-and-extract-region' when you want to allow filtering to
+take place.  For example, major or minor modes can use
+`buffer-substring-filters' to extract characters that are special
+to a buffer, and should not be copied into other buffers."
+  (save-excursion
+    (goto-char beg)
+    (let ((string (if delete (delete-and-extract-region beg end)
+                    (buffer-substring beg end))))
+      (dolist (filter buffer-substring-filters string)
+        (setq string (funcall filter string))))))
+
 ;;;; Window system cut and paste hooks.
 
 (defvar interprogram-cut-function nil
@@ -2309,7 +2439,7 @@ specifies the yank-handler text property to be set on the killed
 text.  See `insert-for-yank'."
   (interactive "r")
   (condition-case nil
-      (let ((string (delete-and-extract-region beg end)))
+      (let ((string (filter-buffer-substring beg end t)))
        (when string                    ;STRING is nil if BEG = END
          ;; Add that string to the kill ring, one way or another.
          (if (eq last-command 'kill-region)
@@ -2345,8 +2475,8 @@ If `interprogram-cut-function' is non-nil, also save the text for a window
 system cut and paste."
   (interactive "r")
   (if (eq last-command 'kill-region)
-      (kill-append (buffer-substring beg end) (< end beg))
-    (kill-new (buffer-substring beg end)))
+      (kill-append (filter-buffer-substring beg end) (< end beg))
+    (kill-new (filter-buffer-substring beg end)))
   (if transient-mark-mode
       (setq deactivate-mark t))
   nil)
@@ -2411,13 +2541,13 @@ The argument is used for internal purposes; do not supply one."
 ;; This is actually used in subr.el but defcustom does not work there.
 (defcustom yank-excluded-properties
   '(read-only invisible intangible field mouse-face help-echo local-map keymap
-    yank-handler)
+    yank-handler follow-link)
   "*Text properties to discard when yanking.
 The value should be a list of text properties to discard or t,
 which means to discard all text properties."
   :type '(choice (const :tag "All" t) (repeat symbol))
   :group 'killing
-  :version "21.4")
+  :version "22.1")
 
 (defvar yank-window-start nil)
 (defvar yank-undo-function nil
@@ -2438,7 +2568,11 @@ With argument N, insert the Nth previous kill.
 If N is negative, this is a more recent kill.
 
 The sequence of kills wraps around, so that after the oldest one
-comes the newest one."
+comes the newest one.
+
+When this command inserts killed text into the buffer, it honors
+`yank-excluded-properties' and `yank-handler' as described in the
+doc string for `insert-for-yank-1', which see."
   (interactive "*p")
   (if (not (eq last-command 'yank))
       (error "Previous command was not a yank"))
@@ -2470,6 +2604,11 @@ killed OR yanked.  Put point at end, and set mark at beginning.
 With just \\[universal-argument] as argument, same but put point at beginning (and mark at end).
 With argument N, reinsert the Nth most recently killed stretch of killed
 text.
+
+When this command inserts killed text into the buffer, it honors
+`yank-excluded-properties' and `yank-handler' as described in the
+doc string for `insert-for-yank-1', which see.
+
 See also the command \\[yank-pop]."
   (interactive "*P")
   (setq yank-window-start (window-start))
@@ -2831,6 +2970,14 @@ START and END specify the portion of the current buffer to be copied."
 (put 'mark-inactive 'error-conditions '(mark-inactive error))
 (put 'mark-inactive 'error-message "The mark is not active now")
 
+(defvar activate-mark-hook nil
+  "Hook run when the mark becomes active.
+It is also run at the end of a command, if the mark is active and
+it is possible that the region may have changed")
+
+(defvar deactivate-mark-hook nil
+  "Hook run when the mark becomes inactive.")
+
 (defun mark (&optional force)
   "Return this buffer's mark value as integer; error if mark inactive.
 If optional argument FORCE is non-nil, access the mark value
@@ -2863,7 +3010,7 @@ the user to see that the mark has moved, and you want the previous
 mark position to be lost.
 
 Normally, when a new mark is set, the old one should go on the stack.
-This is why most applications should use push-mark, not set-mark.
+This is why most applications should use `push-mark', not `set-mark'.
 
 Novice Emacs Lisp programmers often try to use the mark for the wrong
 purposes.  The mark saves a location for the user's convenience.
@@ -2922,6 +3069,7 @@ Display `Mark set' unless the optional second arg NOMSG is non-nil."
     (if (or arg (null mark) (/= mark (point)))
        (push-mark nil nomsg t)
       (setq mark-active t)
+      (run-hooks 'activate-mark-hook)
       (unless nomsg
        (message "Mark activated")))))
 
@@ -3012,10 +3160,10 @@ Does not set point.  Does nothing if mark ring is empty."
   (when mark-ring
     (setq mark-ring (nconc mark-ring (list (copy-marker (mark-marker)))))
     (set-marker (mark-marker) (+ 0 (car mark-ring)) (current-buffer))
-    (deactivate-mark)
     (move-marker (car mark-ring) nil)
     (if (null (mark t)) (ding))
-    (setq mark-ring (cdr mark-ring))))
+    (setq mark-ring (cdr mark-ring)))
+  (deactivate-mark))
 
 (defalias 'exchange-dot-and-mark 'exchange-point-and-mark)
 (defun exchange-point-and-mark (&optional arg)
@@ -3060,6 +3208,14 @@ Invoke \\[apropos-documentation] and type \"transient\" or
 commands which are sensitive to the Transient Mark mode."
   :global t :group 'editing-basics :require nil)
 
+(defvar widen-automatically t
+  "Non-nil means it is ok for commands to call `widen' when they want to.
+Some commands will do this in order to go to positions outside
+the current accessible part of the buffer.
+
+If `widen-automatically' is nil, these commands will do something else
+as a fallback, and won't change the buffer bounds.")
+
 (defun pop-global-mark ()
   "Pop off global mark ring and jump to the top location."
   (interactive)
@@ -3076,7 +3232,9 @@ commands which are sensitive to the Transient Mark mode."
     (set-buffer buffer)
     (or (and (>= position (point-min))
             (<= position (point-max)))
-       (widen))
+       (if widen-automatically
+           (error "Global mark position is outside accessible part of buffer")
+         (widen)))
     (goto-char position)
     (switch-to-buffer buffer)))
 \f
@@ -3086,8 +3244,9 @@ commands which are sensitive to the Transient Mark mode."
   :version "21.1"
   :group 'editing-basics)
 
-(defun next-line (&optional arg)
+(defun next-line (&optional arg try-vscroll)
   "Move cursor vertically down ARG lines.
+Interactively, vscroll tall lines if `auto-window-vscroll' is enabled.
 If there is no character in the target line exactly under the current column,
 the cursor is positioned after the character in that line which spans this
 column, or at the end of the line if it is not long enough.
@@ -3106,7 +3265,7 @@ when there is no goal column.
 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.)."
-  (interactive "p")
+  (interactive "p\np")
   (or arg (setq arg 1))
   (if (and next-line-add-newlines (= arg 1))
       (if (save-excursion (end-of-line) (eobp))
@@ -3114,16 +3273,17 @@ and more reliable (no dependence on goal column, etc.)."
          (let ((abbrev-mode nil))
            (end-of-line)
            (insert "\n"))
-       (line-move arg))
+       (line-move arg nil nil try-vscroll))
     (if (interactive-p)
        (condition-case nil
-           (line-move arg)
+           (line-move arg nil nil try-vscroll)
          ((beginning-of-buffer end-of-buffer) (ding)))
-      (line-move arg)))
+      (line-move arg nil nil try-vscroll)))
   nil)
 
-(defun previous-line (&optional arg)
+(defun previous-line (&optional arg try-vscroll)
   "Move cursor vertically up ARG lines.
+Interactively, vscroll tall lines if `auto-window-vscroll' is enabled.
 If there is no character in the target line exactly over the current column,
 the cursor is positioned after the character in that line which spans this
 column, or at the end of the line if it is not long enough.
@@ -3138,13 +3298,13 @@ when there is no goal column.
 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.)."
-  (interactive "p")
+  (interactive "p\np")
   (or arg (setq arg 1))
   (if (interactive-p)
       (condition-case nil
-         (line-move (- arg))
+         (line-move (- arg) nil nil try-vscroll)
        ((beginning-of-buffer end-of-buffer) (ding)))
-    (line-move (- arg)))
+    (line-move (- arg) nil nil try-vscroll))
   nil)
 
 (defcustom track-eol nil
@@ -3182,10 +3342,50 @@ Outline mode sets this."
       (or (memq prop buffer-invisibility-spec)
          (assq prop buffer-invisibility-spec)))))
 
+;; This is like line-move-1 except that it also performs
+;; vertical scrolling of tall images if appropriate.
+;; That is not really a clean thing to do, since it mixes
+;; scrolling with cursor motion.  But so far we don't have
+;; 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)
+  (if (and auto-window-vscroll try-vscroll
+          ;; But don't vscroll in a keyboard macro.
+          (not defining-kbd-macro)
+          (not executing-kbd-macro))
+      (let ((forward (> arg 0))
+           (part (nth 2 (pos-visible-in-window-p (point) nil t))))
+       (if (and (consp part)
+                (> (if forward (cdr part) (car part)) 0))
+           (set-window-vscroll nil
+                               (if forward
+                                   (+ (window-vscroll nil t)
+                                      (min (cdr part)
+                                           (* (frame-char-height) arg)))
+                                 (max 0
+                                      (- (window-vscroll nil t)
+                                         (min (car part)
+                                              (* (frame-char-height) (- arg))))))
+                               t)
+         (set-window-vscroll nil 0)
+         (when (line-move-1 arg noerror to-end)
+           (when (not forward)
+             ;; Update display before calling pos-visible-in-window-p,
+             ;; because it depends on window-start being up-to-date.
+             (sit-for 0)
+             ;; If the current line is partly hidden at the bottom,
+             ;; scroll it partially up so as to unhide the bottom.
+             (if (and (setq part (nth 2 (pos-visible-in-window-p
+                                         (line-beginning-position) nil t)))
+                      (> (cdr part) 0))
+                 (set-window-vscroll nil (cdr part) t)))
+           t)))
+    (line-move-1 arg noerror to-end)))
+
 ;; This is the guts of next-line and previous-line.
 ;; Arg says how many lines to move.
 ;; The value is t if we can move the specified number of lines.
-(defun line-move (arg &optional noerror to-end)
+(defun line-move-1 (arg &optional noerror to-end)
   ;; Don't run any point-motion hooks, and disregard intangibility,
   ;; for intermediate positions.
   (let ((inhibit-point-motion-hooks t)
@@ -3231,19 +3431,40 @@ Outline mode sets this."
                  (goto-char (next-char-property-change (point))))
                ;; Now move a line.
                (end-of-line)
-               (and (zerop (vertical-motion 1))
-                    (if (not noerror)
-                        (signal 'end-of-buffer nil)
-                      (setq done t)))
+               ;; If there's no invisibility here, move over the newline.
+               (if (and (not (integerp selective-display))
+                        (not (line-move-invisible-p (point))))
+                   ;; We avoid vertical-motion when possible
+                   ;; because that has to fontify.
+                   (if (eobp)
+                       (if (not noerror)
+                           (signal 'end-of-buffer nil)
+                         (setq done t))
+                     (forward-line 1))
+                 ;; Otherwise move a more sophisticated way.
+                 ;; (What's the logic behind this code?)
+                 (and (zerop (vertical-motion 1))
+                      (if (not noerror)
+                          (signal 'end-of-buffer nil)
+                        (setq done t))))
                (unless done
                  (setq arg (1- arg))))
+             ;; The logic of this is the same as the loop above,
+             ;; it just goes in the other direction.
              (while (and (< arg 0) (not done))
                (beginning-of-line)
-
-               (if (zerop (vertical-motion -1))
-                   (if (not noerror)
-                       (signal 'beginning-of-buffer nil)
-                     (setq done t)))
+               (if (or (bobp)
+                       (and (not (integerp selective-display))
+                            (not (line-move-invisible-p (1- (point))))))
+                   (if (bobp)
+                       (if (not noerror)
+                           (signal 'beginning-of-buffer nil)
+                         (setq done t))
+                     (forward-line -1))
+                 (if (zerop (vertical-motion -1))
+                     (if (not noerror)
+                         (signal 'beginning-of-buffer nil)
+                       (setq done t))))
                (unless done
                  (setq arg (1+ arg))
                  (while (and ;; Don't move over previous invis lines
@@ -3398,6 +3619,27 @@ boundaries bind `inhibit-field-text-motion' to t."
              (setq arg 1)
            (setq done t)))))))
 
+(defun move-beginning-of-line (arg)
+  "Move point to beginning of current display line.
+With argument ARG not nil or 1, move forward ARG - 1 lines first.
+If point reaches the beginning or end of buffer, it stops there.
+To ignore intangibility, bind `inhibit-point-motion-hooks' to t.
+
+This command does not move point across a field boundary unless doing so
+would move beyond there to a different line; if ARG is nil or 1, and
+point starts at a field boundary, point does not move.  To ignore field
+boundaries bind `inhibit-field-text-motion' to t."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (if (/= arg 1)
+      (line-move (1- arg) t))
+  (beginning-of-line 1)
+  (let ((orig (point)))
+    (vertical-motion 0)
+    (if (/= orig (point))
+       (goto-char (constrain-to-field (point) orig (/= arg 1) t nil)))))
+
+
 ;;; Many people have said they rarely use this feature, and often type
 ;;; it by accident.  Maybe it shouldn't even be on a key.
 (put 'set-goal-column 'disabled t)
@@ -3431,7 +3673,6 @@ For more details, see the documentation for `scroll-other-window'."
    (if (eq lines '-) nil
      (if (null lines) '-
        (- (prefix-numeric-value lines))))))
-(define-key esc-map [?\C-\S-v] 'scroll-other-window-down)
 
 (defun beginning-of-buffer-other-window (arg)
   "Move point to the beginning of the buffer in the other window.
@@ -3594,7 +3835,7 @@ With argument, do this that many times."
 The place mark goes is the same place \\[forward-word] would
 move to with the same argument.
 Interactively, if this command is repeated
-or (in Transient Mark mode) if the mark is active, 
+or (in Transient Mark mode) if the mark is active,
 it marks the next ARG words after the ones already marked."
   (interactive "P\np")
   (cond ((and allow-extend
@@ -3782,6 +4023,7 @@ Setting this variable automatically makes it local to the current buffer.")
   "The function to use for `auto-fill-function' if Auto Fill mode is turned on.
 Some major modes set this.")
 
+(put 'auto-fill-function :minor-mode-function 'auto-fill-mode)
 ;; FIXME: turn into a proper minor mode.
 ;; Add a global minor mode version of it.
 (defun auto-fill-mode (&optional arg)
@@ -4000,11 +4242,12 @@ when it is off screen)."
                   (setq blinkpos (scan-sexps oldpos -1)))
               (error nil)))
           (and blinkpos
-               (not (eq (car (syntax-after blinkpos)) 8)) ;Not syntax '$'.
+                ;; Not syntax '$'.
+               (not (eq (syntax-class (syntax-after blinkpos)) 8))
                (setq matching-paren
                      (let ((syntax (syntax-after blinkpos)))
                        (and (consp syntax)
-                            (eq (car syntax) 4)
+                            (eq (syntax-class syntax) 4)
                             (cdr syntax)))
                      mismatch
                      (or (null matching-paren)
@@ -4074,8 +4317,6 @@ At top-level, as an editor command, this simply beeps."
   (setq defining-kbd-macro nil)
   (signal 'quit nil))
 
-(define-key global-map "\C-g" 'keyboard-quit)
-
 (defvar buffer-quit-function nil
   "Function to call to \"quit\" the current buffer, or nil if none.
 \\[keyboard-escape-quit] calls this function when its more local actions
@@ -4118,8 +4359,7 @@ specification for `play-sound'."
     (push 'sound sound)
     (play-sound sound)))
 
-(define-key global-map "\e\e\e" 'keyboard-escape-quit)
-
+\f
 (defcustom read-mail-command 'rmail
   "*Your preference for a mail reading package.
 This is used by some keybindings which support reading mail.
@@ -4261,7 +4501,7 @@ Each action has the form (FUNCTION . ARGS)."
    (list nil nil nil current-prefix-arg))
   (compose-mail to subject other-headers continue
                'switch-to-buffer-other-frame yank-action send-actions))
-
+\f
 (defvar set-variable-value-history nil
   "History of values entered with `set-variable'.")
 
@@ -4324,7 +4564,7 @@ With a prefix argument, set VARIABLE to VALUE buffer-locally."
   ;; Force a thorough redisplay for the case that the variable
   ;; has an effect on the display, like `tab-width' has.
   (force-mode-line-update))
-
+\f
 ;; Define the major mode for lists of completions.
 
 (defvar completion-list-mode-map nil
@@ -4332,6 +4572,7 @@ With a prefix argument, set VARIABLE to VALUE buffer-locally."
 (or completion-list-mode-map
     (let ((map (make-sparse-keymap)))
       (define-key map [mouse-2] 'mouse-choose-completion)
+      (define-key map [follow-link] 'mouse-face)
       (define-key map [down-mouse-2] nil)
       (define-key map "\C-m" 'choose-completion)
       (define-key map "\e\e\e" 'delete-completion-window)
@@ -4530,7 +4771,7 @@ Use \\<completion-list-mode-map>\\[mouse-choose-completion] to select one\
   (setq major-mode 'completion-list-mode)
   (make-local-variable 'completion-base-size)
   (setq completion-base-size nil)
-  (run-hooks 'completion-list-mode-hook))
+  (run-mode-hooks 'completion-list-mode-hook))
 
 (defun completion-list-mode-finish ()
   "Finish setup of the completions buffer.
@@ -4599,7 +4840,11 @@ of the differing parts is, by contrast, slightly highlighted."
                    (- (point) (minibuffer-prompt-end)))))
        ;; Otherwise, in minibuffer, the whole input is being completed.
        (if (minibufferp mainbuf)
-           (setq completion-base-size 0)))
+           (if (and (symbolp minibuffer-completion-table)
+                    (get minibuffer-completion-table 'completion-base-size-function))
+               (setq completion-base-size 
+                     (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
@@ -4608,7 +4853,8 @@ of the differing parts is, by contrast, slightly highlighted."
                               (point-min)
                               'mouse-face))
               (element-common-end
-               (+ (or element-start nil) common-string-length))
+               (and element-start
+                    (+ (or element-start nil) common-string-length)))
               (maxp (point-max)))
          (while (and element-start (< element-common-end maxp))
            (when (and (get-char-property element-start 'mouse-face)
@@ -4909,11 +5155,21 @@ the front of the list of recently selected ones."
     (set-buffer buffer)
     (clone-indirect-buffer nil t norecord)))
 
-(define-key ctl-x-4-map "c" 'clone-indirect-buffer-other-window)
 \f
 ;;; Handling of Backspace and Delete keys.
 
-(defcustom normal-erase-is-backspace nil
+(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
@@ -5022,14 +5278,6 @@ See also `normal-erase-is-backspace'."
       (message "Delete key deletes %s"
               (if normal-erase-is-backspace "forward" "backward"))))
 \f
-(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
-wait this many seconds after Emacs becomes idle before doing an update."
-  :type 'number
-  :group 'display
-  :version "21.4")
-\f
 (defvar vis-mode-saved-buffer-invisibility-spec nil
   "Saved value of `buffer-invisibility-spec' when Visible mode is on.")
 
@@ -5041,6 +5289,7 @@ Enabling Visible mode makes all invisible text temporarily visible.
 Disabling Visible mode turns off that effect.  Visible mode
 works by saving the value of `buffer-invisibility-spec' and setting it to nil."
   :lighter " Vis"
+  :group 'editing-basics
   (when (local-variable-p 'vis-mode-saved-buffer-invisibility-spec)
     (setq buffer-invisibility-spec vis-mode-saved-buffer-invisibility-spec)
     (kill-local-variable 'vis-mode-saved-buffer-invisibility-spec))