Use define-derived-mode (and derived-mode-p).
[bpt/emacs.git] / lisp / simple.el
index 138c242..593f36d 100644 (file)
@@ -372,28 +372,6 @@ Other major modes are defined by comparison with this one."
   "Parent major mode from which special major modes should inherit."
   (setq buffer-read-only t))
 
-;; Major mode meant to be the parent of programming modes.
-
-(defvar prog-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [?\C-\M-q] 'prog-indent-sexp)
-    map)
-  "Keymap used for programming modes.")
-
-(defun prog-indent-sexp ()
-  "Indent the expression after point."
-  (interactive)
-  (let ((start (point))
-        (end (save-excursion (forward-sexp 1) (point))))
-    (indent-region start end nil)))
-
-(define-derived-mode prog-mode fundamental-mode "Prog"
-  "Major mode for editing programming language source code."
-  (set (make-local-variable 'require-final-newline) mode-require-final-newline)
-  (set (make-local-variable 'parse-sexp-ignore-comments) t)
-  ;; Any programming language is always written left to right.
-  (setq bidi-paragraph-direction 'left-to-right))
-
 ;; Making and deleting lines.
 
 (defvar hard-newline (propertize "\n" 'hard t 'rear-nonsticky '(hard))
@@ -1236,13 +1214,33 @@ in *Help* buffer.  See also the command `describe-char'."
                   bidi-fixer encoding-msg pos total percent col hscroll))))))
 \f
 ;; Initialize read-expression-map.  It is defined at C level.
-(let ((m (make-sparse-keymap)))
-  (define-key m "\M-\t" 'lisp-complete-symbol)
-  ;; Might as well bind TAB to completion, since inserting a TAB char is much
-  ;; too rarely useful.
-  (define-key m "\t" 'lisp-complete-symbol)
-  (set-keymap-parent m minibuffer-local-map)
-  (setq read-expression-map m))
+(defvar read-expression-map
+  (let ((m (make-sparse-keymap)))
+    (define-key m "\M-\t" 'completion-at-point)
+    ;; Might as well bind TAB to completion, since inserting a TAB char is
+    ;; much too rarely useful.
+    (define-key m "\t" 'completion-at-point)
+    (set-keymap-parent m minibuffer-local-map)
+    m))
+
+(defun read-minibuffer (prompt &optional initial-contents)
+  "Return a Lisp object read using the minibuffer, unevaluated.
+Prompt with PROMPT.  If non-nil, optional second arg INITIAL-CONTENTS
+is a string to insert in the minibuffer before reading.
+\(INITIAL-CONTENTS can also be a cons of a string and an integer.
+Such arguments are used as in `read-from-minibuffer'.)"
+  ;; Used for interactive spec `x'.
+  (read-from-minibuffer prompt initial-contents minibuffer-local-map
+                        t 'minibuffer-history))
+
+(defun eval-minibuffer (prompt &optional initial-contents)
+  "Return value of Lisp expression read using the minibuffer.
+Prompt with PROMPT.  If non-nil, optional second arg INITIAL-CONTENTS
+is a string to insert in the minibuffer before reading.
+\(INITIAL-CONTENTS can also be a cons of a string and an integer.
+Such arguments are used as in `read-from-minibuffer'.)"
+  ;; Used for interactive spec `X'.
+  (eval (read--expression prompt initial-contents)))
 
 (defvar minibuffer-completing-symbol nil
   "Non-nil means completing a Lisp symbol in the minibuffer.")
@@ -1291,6 +1289,20 @@ display the result of expression evaluation."
             (format " (#o%o, #x%x, %s)" value value char-string)
           (format " (#o%o, #x%x)" value value)))))
 
+(defvar eval-expression-minibuffer-setup-hook nil
+  "Hook run by `eval-expression' when entering the minibuffer.")
+
+(defun read--expression (prompt &optional initial-contents)
+  (let ((minibuffer-completing-symbol t))
+    (minibuffer-with-setup-hook
+        (lambda ()
+          (add-hook 'completion-at-point-functions
+                    #'lisp-completion-at-point nil t)
+          (run-hooks 'eval-expression-minibuffer-setup-hook))
+      (read-from-minibuffer prompt initial-contents
+                            read-expression-map t
+                            'read-expression-history))))
+
 ;; We define this, rather than making `eval' interactive,
 ;; for the sake of completion of names like eval-region, eval-buffer.
 (defun eval-expression (exp &optional insert-value)
@@ -1307,10 +1319,7 @@ and `eval-expression-print-level'.
 If `eval-expression-debug-on-error' is non-nil, which is the default,
 this command arranges for all errors to enter the debugger."
   (interactive
-   (list (let ((minibuffer-completing-symbol t))
-          (read-from-minibuffer "Eval: "
-                                nil read-expression-map t
-                                'read-expression-history))
+   (list (read--expression "Eval: ")
         current-prefix-arg))
 
   (if (null eval-expression-debug-on-error)
@@ -1395,11 +1404,27 @@ to get different commands to edit and resubmit."
          ;; add it to the history.
          (or (equal newcmd (car command-history))
              (setq command-history (cons newcmd command-history)))
-         (eval newcmd))
+          (unwind-protect
+              (progn
+                ;; Trick called-interactively-p into thinking that `newcmd' is
+                ;; an interactive call (bug#14136).
+                (add-hook 'called-interactively-p-functions
+                          #'repeat-complex-command--called-interactively-skip)
+                (eval newcmd))
+            (remove-hook 'called-interactively-p-functions
+                         #'repeat-complex-command--called-interactively-skip)))
       (if command-history
          (error "Argument %d is beyond length of command history" arg)
        (error "There are no previous complex commands to repeat")))))
 
+(defun repeat-complex-command--called-interactively-skip (i _frame1 frame2)
+  (and (eq 'eval (cadr frame2))
+       (eq 'repeat-complex-command
+           (cadr (backtrace-frame i #'called-interactively-p)))
+       1))
+
+(defvar extended-command-history nil)
+
 (defun read-extended-command ()
   "Read command name to invoke in `execute-extended-command'."
   (minibuffer-with-setup-hook
@@ -1489,6 +1514,53 @@ give to the command you invoke, if it asks for an argument."
             (sit-for (if (numberp suggest-key-bindings)
                          suggest-key-bindings
                        2))))))))
+
+(defun command-execute (cmd &optional record-flag keys special)
+  ;; BEWARE: Called directly from the C code.
+  "Execute CMD as an editor command.
+CMD must be a symbol that satisfies the `commandp' predicate.
+Optional second arg RECORD-FLAG non-nil
+means unconditionally put this command in the variable `command-history'.
+Otherwise, that is done only if an arg is read using the minibuffer.
+The argument KEYS specifies the value to use instead of (this-command-keys)
+when reading the arguments; if it is nil, (this-command-keys) is used.
+The argument SPECIAL, if non-nil, means that this command is executing
+a special event, so ignore the prefix argument and don't clear it."
+  (setq debug-on-next-call nil)
+  (let ((prefixarg (unless special
+                     (prog1 prefix-arg
+                       (setq current-prefix-arg prefix-arg)
+                       (setq prefix-arg nil)))))
+    (and (symbolp cmd)
+         (get cmd 'disabled)
+         ;; FIXME: Weird calling convention!
+         (run-hooks 'disabled-command-function))
+    (let ((final cmd))
+      (while
+          (progn
+            (setq final (indirect-function final))
+            (if (autoloadp final)
+                (setq final (autoload-do-load final cmd)))))
+      (cond
+       ((arrayp final)
+        ;; If requested, place the macro in the command history.  For
+        ;; other sorts of commands, call-interactively takes care of this.
+        (when record-flag
+          (push `(execute-kbd-macro ,final ,prefixarg) command-history)
+          ;; Don't keep command history around forever.
+          (when (and (numberp history-length) (> history-length 0))
+            (let ((cell (nthcdr history-length command-history)))
+              (if (consp cell) (setcdr cell nil)))))
+        (execute-kbd-macro final prefixarg))
+       (t
+        ;; Pass `cmd' rather than `final', for the backtrace's sake.
+        (prog1 (call-interactively cmd record-flag keys)
+          (when (and (symbolp cmd)
+                     (get cmd 'byte-obsolete-info)
+                     (not (get cmd 'command-execute-obsolete-warned)))
+            (put cmd 'command-execute-obsolete-warned t)
+            (message "%s" (macroexp--obsolete-warning
+                           cmd (get cmd 'byte-obsolete-info) "command")))))))))
 \f
 (defvar minibuffer-history nil
   "Default minibuffer history list.
@@ -2791,10 +2863,11 @@ output is inserted in the current buffer, the buffer `*Shell
 Command Output*' is deleted.
 
 Optional fourth arg OUTPUT-BUFFER specifies where to put the
-command's output.  If the value is a buffer or buffer name, put
-the output there.  Any other value, including nil, means to
-insert the output in the current buffer.  In either case, the
-output is inserted after point (leaving mark after it).
+command's output.  If the value is a buffer or buffer name,
+put the output there.  If the value is nil, use the buffer
+`*Shell Command Output*'.  Any other value, excluding nil,
+means to insert the output in the current buffer.  In either case,
+the output is inserted after point (leaving mark after it).
 
 Optional fifth arg REPLACE, if non-nil, means to insert the
 output in place of text from START to END, putting point and mark
@@ -2841,7 +2914,7 @@ interactively, this is t."
          (goto-char start)
          (and replace (push-mark (point) 'nomsg))
          (setq exit-status
-               (call-process-region start end shell-file-name t
+               (call-process-region start end shell-file-name replace
                                     (if error-file
                                         (list t error-file)
                                       t)
@@ -3082,14 +3155,17 @@ Also, delete any process that is exited or signaled."
   (display-buffer (button-get button 'process-buffer)))
 
 (defun list-processes (&optional query-only buffer)
-  "Display a list of all processes.
+  "Display a list of all processes that are Emacs sub-processes.
 If optional argument QUERY-ONLY is non-nil, only processes with
 the query-on-exit flag set are listed.
 Any process listed as exited or signaled is actually eliminated
 after the listing is made.
 Optional argument BUFFER specifies a buffer to use, instead of
 \"*Process List*\".
-The return value is always nil."
+The return value is always nil.
+
+This function lists only processes that were launched by Emacs.  To
+see other processes running on the system, use `list-system-processes'."
   (interactive)
   (or (fboundp 'process-list)
       (error "Asynchronous subprocesses are not supported on this system"))
@@ -3104,12 +3180,18 @@ The return value is always nil."
   nil)
 \f
 (defvar universal-argument-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [t] 'universal-argument-other-key)
-    (define-key map (vector meta-prefix-char t) 'universal-argument-other-key)
-    (define-key map [switch-frame] nil)
+  (let ((map (make-sparse-keymap))
+        (universal-argument-minus
+         ;; For backward compatibility, minus with no modifiers is an ordinary
+         ;; command if digits have already been entered.
+         `(menu-item "" negative-argument
+                     :filter ,(lambda (cmd)
+                                (if (integerp prefix-arg) nil cmd)))))
+    (define-key map [switch-frame]
+      (lambda (e) (interactive "e")
+        (handle-switch-frame e) (universal-argument--mode)))
     (define-key map [?\C-u] 'universal-argument-more)
-    (define-key map [?-] 'universal-argument-minus)
+    (define-key map [?-] universal-argument-minus)
     (define-key map [?0] 'digit-argument)
     (define-key map [?1] 'digit-argument)
     (define-key map [?2] 'digit-argument)
@@ -3130,30 +3212,12 @@ The return value is always nil."
     (define-key map [kp-7] 'digit-argument)
     (define-key map [kp-8] 'digit-argument)
     (define-key map [kp-9] 'digit-argument)
-    (define-key map [kp-subtract] 'universal-argument-minus)
+    (define-key map [kp-subtract] universal-argument-minus)
     map)
   "Keymap used while processing \\[universal-argument].")
 
-(defvar universal-argument-num-events nil
-  "Number of argument-specifying events read by `universal-argument'.
-`universal-argument-other-key' uses this to discard those events
-from (this-command-keys), and reread only the final command.")
-
-(defvar saved-overriding-map t
-  "The saved value of `overriding-terminal-local-map'.
-That variable gets restored to this value on exiting \"universal
-argument mode\".")
-
-(defun save&set-overriding-map (map)
-  "Set `overriding-terminal-local-map' to MAP."
-  (when (eq saved-overriding-map t)
-    (setq saved-overriding-map overriding-terminal-local-map)
-    (setq overriding-terminal-local-map map)))
-
-(defun restore-overriding-map ()
-  "Restore `overriding-terminal-local-map' to its saved value."
-  (setq overriding-terminal-local-map saved-overriding-map)
-  (setq saved-overriding-map t))
+(defun universal-argument--mode ()
+  (set-temporary-overlay-map universal-argument-map))
 
 (defun universal-argument ()
   "Begin a numeric argument for the following command.
@@ -3167,33 +3231,27 @@ which is different in effect from any particular numeric argument.
 These commands include \\[set-mark-command] and \\[start-kbd-macro]."
   (interactive)
   (setq prefix-arg (list 4))
-  (setq universal-argument-num-events (length (this-command-keys)))
-  (save&set-overriding-map universal-argument-map))
+  (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.
 (defun universal-argument-more (arg)
+  ;; 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")
-  (if (consp arg)
-      (setq prefix-arg (list (* 4 (car arg))))
-    (if (eq arg '-)
-       (setq prefix-arg (list -4))
-      (setq prefix-arg arg)
-      (restore-overriding-map)))
-  (setq universal-argument-num-events (length (this-command-keys))))
+  (setq prefix-arg (if (consp arg)
+                       (list (* 4 (car arg)))
+                     (if (eq arg '-)
+                         (list -4)
+                       arg)))
+  (when (consp prefix-arg) (universal-argument--mode)))
 
 (defun negative-argument (arg)
   "Begin a negative numeric argument for the next command.
 \\[universal-argument] following digits or minus sign ends the argument."
   (interactive "P")
-  (cond ((integerp arg)
-        (setq prefix-arg (- arg)))
-       ((eq arg '-)
-        (setq prefix-arg nil))
-       (t
-        (setq prefix-arg '-)))
-  (setq universal-argument-num-events (length (this-command-keys)))
-  (save&set-overriding-map universal-argument-map))
+  (setq prefix-arg (cond ((integerp arg) (- arg))
+                         ((eq arg '-) nil)
+                         (t '-)))
+  (universal-argument--mode))
 
 (defun digit-argument (arg)
   "Part of the numeric argument for the next command.
@@ -3203,80 +3261,45 @@ These commands include \\[set-mark-command] and \\[start-kbd-macro]."
                   last-command-event
                 (get last-command-event 'ascii-character)))
         (digit (- (logand char ?\177) ?0)))
-    (cond ((integerp arg)
-          (setq prefix-arg (+ (* arg 10)
-                              (if (< arg 0) (- digit) digit))))
-         ((eq arg '-)
-          ;; Treat -0 as just -, so that -01 will work.
-          (setq prefix-arg (if (zerop digit) '- (- digit))))
-         (t
-          (setq prefix-arg digit))))
-  (setq universal-argument-num-events (length (this-command-keys)))
-  (save&set-overriding-map universal-argument-map))
-
-;; For backward compatibility, minus with no modifiers is an ordinary
-;; command if digits have already been entered.
-(defun universal-argument-minus (arg)
-  (interactive "P")
-  (if (integerp arg)
-      (universal-argument-other-key arg)
-    (negative-argument arg)))
-
-;; Anything else terminates the argument and is left in the queue to be
-;; executed as a command.
-(defun universal-argument-other-key (arg)
-  (interactive "P")
-  (setq prefix-arg arg)
-  (let* ((key (this-command-keys))
-        (keylist (listify-key-sequence key)))
-    (setq unread-command-events
-         (append (nthcdr universal-argument-num-events keylist)
-                 unread-command-events)))
-  (reset-this-command-lengths)
-  (restore-overriding-map))
+    (setq prefix-arg (cond ((integerp arg)
+                            (+ (* arg 10)
+                              (if (< arg 0) (- digit) digit)))
+                           ((eq arg '-)
+                            ;; Treat -0 as just -, so that -01 will work.
+                            (if (zerop digit) '- (- digit)))
+                           (t
+                            digit))))
+  (universal-argument--mode))
 \f
 
 (defvar filter-buffer-substring-functions nil
-  "This variable is a wrapper hook around `filter-buffer-substring'.
-Each member of the hook should be a function accepting four arguments:
-\(FUN BEG END DELETE), where FUN is itself a function of three arguments
+  "This variable is a wrapper hook around `filter-buffer-substring'.")
+(make-obsolete-variable 'filter-buffer-substring-functions
+                        'filter-buffer-substring-function "24.4")
+
+(defvar filter-buffer-substring-function #'buffer-substring--filter
+  "Function to perform the filtering in `filter-buffer-substring'.
+The function is called with 3 arguments:
 \(BEG END DELETE).  The arguments BEG, END, and DELETE are the same
 as those of `filter-buffer-substring' in each case.
-
-The first hook function to be called receives a FUN equivalent
-to the default operation of `filter-buffer-substring',
-i.e. one that returns the buffer-substring between BEG and
-END (processed by any `buffer-substring-filters').  Normally,
-the hook function will call FUN and then do its own processing
-of the result.  The next hook function receives a FUN equivalent
-to the previous hook function, calls it, and does its own
-processing, and so on.  The overall result is that of all hook
-functions acting in sequence.
-
-Any hook may choose not to call FUN though, in which case it
-effectively replaces the default behavior with whatever it chooses.
-Of course, a later hook function may do the same thing.")
+It should return the buffer substring between BEG and END, after filtering.")
 
 (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 final result (if `buffer-substring-filters' is
-nil, this is the unfiltered buffer-substring) is passed to the
-first function on `filter-buffer-substring-functions'.
-
+the next.
 As a special convention, point is set to the start of the buffer text
 being operated on (i.e., the first argument of `filter-buffer-substring')
 before these functions are called.")
 (make-obsolete-variable 'buffer-substring-filters
-                        'filter-buffer-substring-functions "24.1")
+                        'filter-buffer-substring-function "24.1")
 
 (defun filter-buffer-substring (beg end &optional delete)
   "Return the buffer substring between BEG and END, after filtering.
-The wrapper hook `filter-buffer-substring-functions' performs
-the actual filtering.  The obsolete variable `buffer-substring-filters'
-is also consulted.  If both of these are nil, no filtering is done.
+The hook `filter-buffer-substring-function' performs the actual filtering.
+By default, no filtering is done.
 
 If DELETE is non-nil, the text between BEG and END is deleted
 from the buffer.
@@ -3284,9 +3307,13 @@ from the buffer.
 This function should be used instead of `buffer-substring',
 `buffer-substring-no-properties', or `delete-and-extract-region'
 when you want to allow filtering to take place.  For example,
-major or minor modes can use `filter-buffer-substring-functions' to
+major or minor modes can use `filter-buffer-substring-function' to
 extract characters that are special to a buffer, and should not
 be copied into other buffers."
+  (funcall filter-buffer-substring-function beg end delete))
+
+;; FIXME: `with-wrapper-hook' is obsolete
+(defun buffer-substring--filter (beg end &optional delete)
   (with-wrapper-hook filter-buffer-substring-functions (beg end delete)
     (cond
      ((or delete buffer-substring-filters)
@@ -4046,9 +4073,9 @@ Don't call it from programs: use `insert-buffer-substring' instead!"
     (progn
       (barf-if-buffer-read-only)
       (read-buffer "Insert buffer: "
-                  (if (eq (selected-window) (next-window (selected-window)))
+                  (if (eq (selected-window) (next-window))
                       (other-buffer (current-buffer))
-                    (window-buffer (next-window (selected-window))))
+                    (window-buffer (next-window)))
                   t))))
   (push-mark
    (save-excursion
@@ -4108,8 +4135,7 @@ START and END specify the portion of the current buffer to be copied."
       (save-excursion
        (insert-buffer-substring oldbuf start end)))))
 \f
-(put 'mark-inactive 'error-conditions '(mark-inactive error))
-(put 'mark-inactive 'error-message (purecopy "The mark is not active now"))
+(define-error 'mark-inactive (purecopy "The mark is not active now"))
 
 (defvar activate-mark-hook nil
   "Hook run when the mark becomes active.
@@ -4133,7 +4159,7 @@ a mistake; see the documentation of `set-mark'."
       (marker-position (mark-marker))
     (signal 'mark-inactive nil)))
 
-(defsubst deactivate-mark (&optional force)
+(defun deactivate-mark (&optional force)
   "Deactivate the mark.
 If Transient Mark mode is disabled, this function normally does
 nothing; but if FORCE is non-nil, it deactivates the mark anyway.
@@ -4553,6 +4579,12 @@ for it.")
 (defun next-line (&optional arg try-vscroll)
   "Move cursor vertically down ARG lines.
 Interactively, vscroll tall lines if `auto-window-vscroll' is enabled.
+Non-interactively, use TRY-VSCROLL to control whether to vscroll tall
+lines: if either `auto-window-vscroll' or TRY-VSCROLL is nil, this
+function will not vscroll.
+
+ARG defaults to 1.
+
 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.
@@ -4597,6 +4629,12 @@ and more reliable (no dependence on goal column, etc.)."
 (defun previous-line (&optional arg try-vscroll)
   "Move cursor vertically up ARG lines.
 Interactively, vscroll tall lines if `auto-window-vscroll' is enabled.
+Non-interactively, use TRY-VSCROLL to control whether to vscroll tall
+lines: if either `auto-window-vscroll' or TRY-VSCROLL is nil, this
+function will not vscroll.
+
+ARG defaults to 1.
+
 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.
@@ -4676,61 +4714,156 @@ lines."
   :group 'editing-basics
   :version "23.1")
 
+(defun default-font-height ()
+  "Return the height in pixels of the current buffer's default face font."
+  (let ((default-font (face-font 'default)))
+    (cond
+     ((and (display-multi-font-p)
+          ;; Avoid calling font-info if the frame's default font was
+          ;; not changed since the frame was created.  That's because
+          ;; font-info is expensive for some fonts, see bug #14838.
+          (not (string= (frame-parameter nil 'font) default-font)))
+      (aref (font-info default-font) 3))
+     (t (frame-char-height)))))
+
+(defun default-line-height ()
+  "Return the pixel height of current buffer's default-face text line.
+
+The value includes `line-spacing', if any, defined for the buffer
+or the frame."
+  (let ((dfh (default-font-height))
+       (lsp (if (display-graphic-p)
+                (or line-spacing
+                    (default-value 'line-spacing)
+                    (frame-parameter nil 'line-spacing)
+                    0)
+              0)))
+    (if (floatp lsp)
+       (setq lsp (* dfh lsp)))
+    (+ dfh lsp)))
+
+(defun window-screen-lines ()
+  "Return the number of screen lines in the text area of the selected window.
+
+This is different from `window-text-height' in that this function counts
+lines in units of the height of the font used by the default face displayed
+in the window, not in units of the frame's default font, and also accounts
+for `line-spacing', if any, defined for the window's buffer or frame.
+
+The value is a floating-point number."
+  (let ((canonical (window-text-height))
+       (fch (frame-char-height))
+       (dlh (default-line-height)))
+    (/ (* (float canonical) fch) dlh)))
+
 ;; Returns non-nil if partial move was done.
 (defun line-move-partial (arg noerror to-end)
   (if (< arg 0)
       ;; Move backward (up).
       ;; If already vscrolled, reduce vscroll
-      (let ((vs (window-vscroll nil t)))
-       (when (> vs (frame-char-height))
-         (set-window-vscroll nil (- vs (frame-char-height)) t)))
+      (let ((vs (window-vscroll nil t))
+           (dlh (default-line-height)))
+       (when (> vs dlh)
+         (set-window-vscroll nil (- vs dlh) t)))
 
     ;; Move forward (down).
     (let* ((lh (window-line-height -1))
+          (rowh (car lh))
           (vpos (nth 1 lh))
           (ypos (nth 2 lh))
           (rbot (nth 3 lh))
-          py vs)
+          (this-lh (window-line-height))
+          (this-height (car this-lh))
+          (this-ypos (nth 2 this-lh))
+          (dlh (default-line-height))
+          (wslines (window-screen-lines))
+          (edges (window-inside-pixel-edges))
+          (winh (- (nth 3 edges) (nth 1 edges) 1))
+          py vs last-line)
+      (if (> (mod wslines 1.0) 0.0)
+         (setq wslines (round (+ wslines 0.5))))
       (when (or (null lh)
-               (>= rbot (frame-char-height))
-               (<= ypos (- (frame-char-height))))
+               (>= rbot dlh)
+               (<= ypos (- dlh))
+               (null this-lh)
+               (<= this-ypos (- dlh)))
        (unless lh
          (let ((wend (pos-visible-in-window-p t nil t)))
            (setq rbot (nth 3 wend)
+                 rowh  (nth 4 wend)
                  vpos (nth 5 wend))))
+       (unless this-lh
+         (let ((wstart (pos-visible-in-window-p nil nil t)))
+           (setq this-ypos (nth 2 wstart)
+                 this-height (nth 4 wstart))))
+       (setq py
+             (or (nth 1 this-lh)
+                 (let ((ppos (posn-at-point))
+                       col-row)
+                   (setq col-row (posn-actual-col-row ppos))
+                   (if col-row
+                       (- (cdr col-row) (window-vscroll))
+                     (cdr (posn-col-row ppos))))))
+       ;; VPOS > 0 means the last line is only partially visible.
+       ;; But if the part that is visible is at least as tall as the
+       ;; default font, that means the line is actually fully
+       ;; readable, and something like line-spacing is hidden.  So in
+       ;; that case we accept the last line in the window as still
+       ;; visible, and consider the margin as starting one line
+       ;; later.
+       (if (and vpos (> vpos 0))
+           (if (and rowh
+                    (>= rowh (default-font-height))
+                    (< rowh dlh))
+               (setq last-line (min (- wslines scroll-margin) vpos))
+             (setq last-line (min (- wslines scroll-margin 1) (1- vpos)))))
        (cond
-        ;; If last line of window is fully visible, move forward.
-        ((or (null rbot) (= rbot 0))
+        ;; If last line of window is fully visible, and vscrolling
+        ;; more would make this line invisible, move forward.
+        ((and (or (< (setq vs (window-vscroll nil t)) dlh)
+                  (null this-height)
+                  (<= this-height dlh))
+              (or (null rbot) (= rbot 0)))
          nil)
-        ;; If cursor is not in the bottom scroll margin, move forward.
-        ((and (> vpos 0)
-              (< (setq py
-                       (or (nth 1 (window-line-height))
-                           (let ((ppos (posn-at-point)))
-                             (cdr (or (posn-actual-col-row ppos)
-                                      (posn-col-row ppos))))))
-                 (min (- (window-text-height) scroll-margin 1) (1- vpos))))
+        ;; If cursor is not in the bottom scroll margin, and the
+        ;; current line is is not too tall, move forward.
+        ((and (or (null this-height) (<= this-height winh))
+              vpos
+              (> vpos 0)
+              (< py last-line))
          nil)
         ;; When already vscrolled, we vscroll some more if we can,
         ;; or clear vscroll and move forward at end of tall image.
-        ((> (setq vs (window-vscroll nil t)) 0)
-         (when (> rbot 0)
-           (set-window-vscroll nil (+ vs (min rbot (frame-char-height))) t)))
+        ((> vs 0)
+         (when (or (and rbot (> rbot 0))
+                   (and this-height (> this-height dlh)))
+           (set-window-vscroll nil (+ vs dlh) t)))
         ;; If cursor just entered the bottom scroll margin, move forward,
-        ;; but also vscroll one line so redisplay won't recenter.
-        ((and (> vpos 0)
-              (= py (min (- (window-text-height) scroll-margin 1)
-                         (1- vpos))))
-         (set-window-vscroll nil (frame-char-height) t)
+        ;; but also optionally vscroll one line so redisplay won't recenter.
+        ((and vpos
+              (> vpos 0)
+              (= py last-line))
+         ;; Don't vscroll if the partially-visible line at window
+         ;; bottom is not too tall (a.k.a. "just one more text
+         ;; line"): in that case, we do want redisplay to behave
+         ;; normally, i.e. recenter or whatever.
+         ;;
+         ;; Note: ROWH + RBOT from the value returned by
+         ;; pos-visible-in-window-p give the total height of the
+         ;; partially-visible glyph row at the end of the window.  As
+         ;; we are dealing with floats, we disregard sub-pixel
+         ;; discrepancies between that and DLH.
+         (if (and rowh rbot (>= (- (+ rowh rbot) winh) 1))
+             (set-window-vscroll nil dlh t))
          (line-move-1 arg noerror to-end)
          t)
         ;; If there are lines above the last line, scroll-up one line.
-        ((> vpos 0)
+        ((and vpos (> vpos 0))
          (scroll-up 1)
          t)
         ;; Finally, start vscroll.
         (t
-         (set-window-vscroll nil (frame-char-height) t)))))))
+         (set-window-vscroll nil dlh t)))))))
 
 
 ;; This is like line-move-1 except that it also performs
@@ -4760,7 +4893,20 @@ lines."
               ;; display-based motion doesn't make sense (because each
               ;; logical line occupies exactly one screen line).
               (not (> (window-hscroll) 0)))
-         (line-move-visual arg noerror)
+         (prog1 (line-move-visual arg noerror)
+           ;; If we moved into a tall line, set vscroll to make
+           ;; scrolling through tall images more smooth.
+           (let ((lh (line-pixel-height))
+                 (edges (window-inside-pixel-edges))
+                 (dlh (default-line-height))
+                 winh)
+             (setq winh (- (nth 3 edges) (nth 1 edges) 1))
+             (if (and (< arg 0)
+                      (< (point) (window-start))
+                      (> lh winh))
+                 (set-window-vscroll
+                  nil
+                  (- lh dlh) t))))
        (line-move-1 arg noerror to-end)))))
 
 ;; Display-based alternative to line-move-1.
@@ -4791,13 +4937,25 @@ lines."
                         (frame-char-width)) hscroll))))))
     (if target-hscroll
        (set-window-hscroll (selected-window) target-hscroll))
-    (or (and (= (vertical-motion
-                (cons (or goal-column
-                          (if (consp temporary-goal-column)
-                              (car temporary-goal-column)
-                            temporary-goal-column))
-                      arg))
-               arg)
+    ;; vertical-motion can move more than it was asked to if it moves
+    ;; across display strings with newlines.  We don't want to ring
+    ;; the bell and announce beginning/end of buffer in that case.
+    (or (and (or (and (>= arg 0)
+                     (>= (vertical-motion
+                          (cons (or goal-column
+                                    (if (consp temporary-goal-column)
+                                        (car temporary-goal-column)
+                                      temporary-goal-column))
+                                arg))
+                         arg))
+                (and (< arg 0)
+                     (<= (vertical-motion
+                          (cons (or goal-column
+                                    (if (consp temporary-goal-column)
+                                        (car temporary-goal-column)
+                                      temporary-goal-column))
+                                arg))
+                         arg)))
             (or (>= arg 0)
                 (/= (point) opoint)
                 ;; If the goal column lies on a display string,
@@ -5349,8 +5507,7 @@ Mode' for details."
   (visual-line-mode 1))
 
 (define-globalized-minor-mode global-visual-line-mode
-  visual-line-mode turn-on-visual-line-mode
-  :lighter " vl")
+  visual-line-mode turn-on-visual-line-mode)
 
 \f
 (defun transpose-chars (arg)
@@ -5488,7 +5645,8 @@ current object."
 \f
 (defun backward-word (&optional arg)
   "Move backward until encountering the beginning of a word.
-With argument ARG, do this that many times."
+With argument ARG, do this that many times.
+If ARG is omitted or nil, move point backward one word."
   (interactive "^p")
   (forward-word (- (or arg 1))))
 
@@ -5782,7 +5940,7 @@ The variable `selective-display' has a separate value for each buffer."
     (setq selective-display
          (and arg (prefix-numeric-value arg)))
     (recenter current-vpos))
-  (set-window-start (selected-window) (window-start (selected-window)))
+  (set-window-start (selected-window) (window-start))
   (princ "selective-display set to " t)
   (prin1 selective-display t)
   (princ "." t))
@@ -6360,10 +6518,10 @@ With a prefix argument, set VARIABLE to VALUE buffer-locally."
                      (call-interactively `(lambda (arg)
                                             (interactive ,prop)
                                             arg))
-                   (read
-                    (read-string prompt nil
-                                 'set-variable-value-history
-                                (format "%S" (symbol-value var))))))))
+                   (read-from-minibuffer prompt nil
+                                         read-expression-map t
+                                         'set-variable-value-history
+                                         (format "%S" (symbol-value var)))))))
      (list var val current-prefix-arg)))
 
   (and (custom-variable-p variable)
@@ -6446,8 +6604,7 @@ Go to the window from which completion was requested."
   (interactive)
   (let ((buf completion-reference-buffer))
     (if (one-window-p t)
-       (if (window-dedicated-p (selected-window))
-           (delete-frame (selected-frame)))
+       (if (window-dedicated-p) (delete-frame))
       (delete-window (selected-window))
       (if (get-buffer-window buf)
          (select-window (get-buffer-window buf))))))
@@ -6574,7 +6731,9 @@ the default method of inserting the completion in BUFFER.")
 (defun choose-completion-string (choice &optional
                                         buffer base-position insert-function)
   "Switch to BUFFER and insert the completion choice CHOICE.
-BASE-POSITION, says where to insert the completion."
+BASE-POSITION says where to insert the completion.
+INSERT-FUNCTION says how to insert the completion and falls
+back on `completion-list-insert-choice-function' when nil."
 
   ;; If BUFFER is the minibuffer, exit the minibuffer
   ;; unless it is reading a file name and CHOICE is a directory,
@@ -6668,15 +6827,21 @@ Called from `temp-buffer-show-hook'."
 (defun completion-setup-function ()
   (let* ((mainbuf (current-buffer))
          (base-dir
-          ;; When reading a file name in the minibuffer,
-          ;; try and find the right default-directory to set in the
-          ;; completion list buffer.
-          ;; FIXME: Why do we do that, actually?  --Stef
+          ;; FIXME: This is a bad hack.  We try to set the default-directory
+          ;; in the *Completions* buffer so that the relative file names
+          ;; displayed there can be treated as valid file names, independently
+          ;; from the completion context.  But this suffers from many problems:
+          ;; - It's not clear when the completions are file names.  With some
+          ;;   completion tables (e.g. bzr revision specs), the listed
+          ;;   completions can mix file names and other things.
+          ;; - It doesn't pay attention to possible quoting.
+          ;; - With fancy completion styles, the code below will not always
+          ;;   find the right base directory.
           (if minibuffer-completing-file-name
               (file-name-as-directory
                (expand-file-name
-                (substring (minibuffer-completion-contents)
-                           0 (or completion-base-size 0)))))))
+                (buffer-substring (minibuffer-prompt-end)
+                                  (- (point) (or completion-base-size 0))))))))
     (with-current-buffer standard-output
       (let ((base-size completion-base-size) ;Read before killing localvars.
             (base-position completion-base-position)
@@ -7227,8 +7392,7 @@ version and use the one distributed with Emacs."))
   "Alist of packages known to cause problems in this version of Emacs.
 Each element has the form (PACKAGE SYMBOL REGEXP STRING).
 PACKAGE is either a regular expression to match file names, or a
-symbol (a feature name); see the documentation of
-`after-load-alist', to which this variable adds functions.
+symbol (a feature name), like for `with-eval-after-load'.
 SYMBOL is either the name of a string variable, or `t'.  Upon
 loading PACKAGE, if SYMBOL is t or matches REGEXP, display a
 warning using STRING as the message.")
@@ -7246,10 +7410,70 @@ warning using STRING as the message.")
              (display-warning package (nth 3 list) :warning)))
     (error nil)))
 
-(mapc (lambda (elem)
-        (eval-after-load (car elem) `(bad-package-check ',(car elem))))
-      bad-packages-alist)
+(dolist (elem bad-packages-alist)
+  (let ((pkg (car elem)))
+    (with-eval-after-load pkg
+      (bad-package-check pkg))))
+
+\f
+;;; Generic dispatcher commands
 
+;; Macro `define-alternatives' is used to create generic commands.
+;; Generic commands are these (like web, mail, news, encrypt, irc, etc.)
+;; that can have different alternative implementations where choosing
+;; among them is exclusively a matter of user preference.
+
+;; (define-alternatives COMMAND) creates a new interactive command
+;; M-x COMMAND and a customizable variable COMMAND-alternatives.
+;; Typically, the user will not need to customize this variable; packages
+;; wanting to add alternative implementations should use
+;;
+;; ;;;###autoload (push '("My impl name" . my-impl-symbol) COMMAND-alternatives
+
+(defmacro define-alternatives (command &rest customizations)
+  "Define new command `COMMAND'.
+The variable `COMMAND-alternatives' will contain alternative
+implementations of COMMAND, so that running `C-u M-x COMMAND'
+will allow the user to chose among them.
+CUSTOMIZATIONS, if non-nil, should be composed of alternating
+`defcustom' keywords and values to add to the declaration of
+`COMMAND-alternatives' (typically :group and :version)."
+  (let* ((command-name (symbol-name command))
+         (varalt-name (concat command-name "-alternatives"))
+         (varalt-sym (intern varalt-name))
+         (varimp-sym (intern (concat command-name "--implementation"))))
+    `(progn
+
+       (defcustom ,varalt-sym nil
+         ,(format "Alist of alternative implementations for the `%s' command.
+
+Each entry must be a pair (ALTNAME . ALTFUN), where:
+ALTNAME - The name shown at user to describe the alternative implementation.
+ALTFUN  - The function called to implement this alternative."
+                  command-name)
+         :type '(alist :key-type string :value-type function)
+         ,@customizations)
+
+       (defvar ,varimp-sym nil "Internal use only.")
+
+       (defun ,command (&optional arg)
+         ,(format "Run generic command `%s'.
+If used for the first time, or with interactive ARG, ask the user which
+implementation to use for `%s'.  The variable `%s'
+contains the list of implementations currently supported for this command."
+                  command-name command-name varalt-name)
+         (interactive "P")
+         (when (or arg (null ,varimp-sym))
+           (let ((val (completing-read
+                       ,(format "Select implementation for command `%s': " command-name)
+                       ,varalt-sym nil t)))
+             (unless (string-equal val "")
+               (customize-save-variable ',varimp-sym
+                                        (cdr (assoc-string val ,varalt-sym))))))
+         (if ,varimp-sym
+             (funcall ,varimp-sym)
+           (message ,(format "No implementation selected for command `%s'"
+                             command-name)))))))
 
 (provide 'simple)