(imenu-use-keymap-menu): New variable.
[bpt/emacs.git] / lisp / simple.el
index 5d0058d..abe7421 100644 (file)
@@ -1,6 +1,6 @@
 ;;; simple.el --- basic editing commands for Emacs
 
-;; Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (defun newline (&optional arg)
-  "Insert a newline and move to left margin of the new line.
+  "Insert a newline, and move to left margin of the new line if it's blank.
 The newline is marked with the text-property `hard'.
 With arg, insert that many newlines.
 In Auto Fill mode, if no numeric arg, break the preceding line if it's long."
@@ -38,13 +38,18 @@ In Auto Fill mode, if no numeric arg, break the preceding line if it's long."
   (let ((flag (and (not (bobp)) 
                   (bolp)
                   (< (or (previous-property-change (point)) -2) 
-                     (- (point) 2)))))
+                     (- (point) 2))))
+       (was-page-start (and (bolp)
+                            (looking-at page-delimiter)))
+       (beforepos (point)))
     (if flag (backward-char 1))
     ;; Call self-insert so that auto-fill, abbrev expansion etc. happens.
     ;; Set last-command-char to tell self-insert what to insert.
     (let ((last-command-char ?\n)
          ;; Don't auto-fill if we have a numeric argument.
-         (auto-fill-function (if arg nil auto-fill-function)))
+         ;; Also not if flag is true (it would fill wrong line);
+         ;; there is no need to since we're at BOL.
+         (auto-fill-function (if (or arg flag) nil auto-fill-function)))
       (self-insert-command (prefix-numeric-value arg)))
     ;; Mark the newline(s) `hard'.
     (if use-hard-newlines
@@ -55,26 +60,42 @@ In Auto Fill mode, if no numeric arg, break the preceding line if it's long."
          (if (and (listp sticky) (not (memq 'hard sticky)))
              (put-text-property from (point) 'rear-nonsticky
                                 (cons 'hard sticky)))))
-    (if flag (forward-char 1)))
-  (move-to-left-margin nil t)
+    ;; If the newline leaves the previous line blank,
+    ;; and we have a left margin, delete that from the blank line.
+    (or flag
+       (save-excursion
+         (goto-char beforepos)
+         (beginning-of-line)
+         (and (looking-at "[ \t]$")
+              (> (current-left-margin) 0)
+              (delete-region (point) (progn (end-of-line) (point))))))
+    (if flag (forward-char 1))
+    ;; Indent the line after the newline, except in one case:
+    ;; when we added the newline at the beginning of a line
+    ;; which starts a page.
+    (or was-page-start
+       (move-to-left-margin nil t)))
   nil)
 
 (defun open-line (arg)
   "Insert a newline and leave point before it.
 If there is a fill prefix and/or a left-margin, insert them on the new line
-if the line would have been empty.
+if the line would have been blank.
 With arg N, insert N newlines."
   (interactive "*p")
   (let* ((do-fill-prefix (and fill-prefix (bolp)))
         (do-left-margin (and (bolp) (> (current-left-margin) 0)))
         (loc (point)))
+    (newline arg)
+    (goto-char loc)
     (while (> arg 0)
-      (if do-left-margin (indent-to (current-left-margin)))
-      (if do-fill-prefix (insert-and-inherit fill-prefix))
-      (newline 1)
+      (cond ((bolp)
+            (if do-left-margin (indent-to (current-left-margin)))
+            (if do-fill-prefix (insert-and-inherit fill-prefix))))
+      (forward-line 1)
       (setq arg (1- arg)))
-    (goto-char loc))
-  (end-of-line))
+    (goto-char loc)
+    (end-of-line)))
 
 (defun split-line ()
   "Split current line, moving portion beyond point vertically down."
@@ -542,8 +563,9 @@ If N is negative, find the next or Nth next match."
                                        'minibuffer-history-search-history)))
      ;; Use the last regexp specified, by default, if input is empty.
      (list (if (string= regexp "")
-              (setcar minibuffer-history-search-history
-                      (nth 1 minibuffer-history-search-history))
+              (if minibuffer-history-search-history
+                  (car minibuffer-history-search-history)
+                (error "No previous history search regexp"))
             regexp)
           (prefix-numeric-value current-prefix-arg))))
   (let ((history (symbol-value minibuffer-history-variable))
@@ -712,8 +734,17 @@ then call `undo-more' one or more times to undo them."
 
 (defun shell-command (command &optional output-buffer)
   "Execute string COMMAND in inferior shell; display output, if any.
+
 If COMMAND ends in ampersand, execute it asynchronously.
-The output appears in the buffer `*Shell Command*'.
+The output appears in the buffer `*Async Shell Command*'.
+
+Otherwise, COMMAND is executed synchronously.  The output appears
+in the buffer `*Shell Command Output*'.
+If the output is one line, it is displayed in the echo area *as well*,
+but it is nonetheless available in buffer `*Shell Command Output*',
+even though that buffer is not automatically displayed.
+If there is no output, or if output is inserted in the current buffer,
+then `*Shell Command Output*' is deleted.
 
 The optional second argument OUTPUT-BUFFER, if non-nil,
 says to put the output in some other buffer.
@@ -747,7 +778,7 @@ In either case, the output is inserted after point (leaving mark after it)."
          (if (string-match "[ \t]*&[ \t]*$" command)
              ;; Command ending with ampersand means asynchronous.
              (let ((buffer (get-buffer-create
-                            (or output-buffer "*Shell-Command*")))
+                            (or output-buffer "*Asynch Shell Command*")))
                    (directory default-directory)
                    proc)
                ;; Remove the ampersand.
@@ -904,6 +935,102 @@ In either case, the output is inserted after point (leaving mark after it)."
                (t 
                 (set-window-start (display-buffer buffer) 1))))))))
 \f
+(defconst 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)
+    (define-key map [?\C-u] 'universal-argument-more)
+    (define-key map [?-] 'universal-argument-minus)
+    (define-key map [?0] 'digit-argument)
+    (define-key map [?1] 'digit-argument)
+    (define-key map [?2] 'digit-argument)
+    (define-key map [?3] 'digit-argument)
+    (define-key map [?4] 'digit-argument)
+    (define-key map [?5] 'digit-argument)
+    (define-key map [?6] 'digit-argument)
+    (define-key map [?7] 'digit-argument)
+    (define-key map [?8] 'digit-argument)
+    (define-key map [?9] 'digit-argument)
+    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.")
+
+(defun universal-argument ()
+  "Begin a numeric argument for the following command.
+Digits or minus sign following \\[universal-argument] make up the numeric argument.
+\\[universal-argument] following the digits or minus sign ends the argument.
+\\[universal-argument] without digits or minus sign provides 4 as argument.
+Repeating \\[universal-argument] without digits or minus sign
+ multiplies the argument by 4 each time."
+  (interactive)
+  (setq prefix-arg (list 4))
+  (setq universal-argument-num-events (length (this-command-keys)))
+  (setq overriding-terminal-local-map universal-argument-map))
+
+;; 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)
+  (interactive "P")
+  (if (consp arg)
+      (setq prefix-arg (list (* 4 (car arg))))
+    (setq prefix-arg arg)
+    (setq overriding-terminal-local-map nil))
+  (setq universal-argument-num-events (length (this-command-keys))))
+
+(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)))
+  (setq overriding-terminal-local-map universal-argument-map))
+
+(defun digit-argument (arg)
+  "Part of the numeric argument for the next command.
+\\[universal-argument] following digits or minus sign ends the argument."
+  (interactive "P")
+  (let ((digit (- (logand last-command-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)))
+  (setq overriding-terminal-local-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
+         (nthcdr universal-argument-num-events keylist)))
+  (reset-this-command-lengths)
+  (setq overriding-terminal-local-map nil))
+\f
 (defun forward-to-indentation (arg)
   "Move forward ARG lines and position at first nonblank character."
   (interactive "p")
@@ -1304,13 +1431,6 @@ START and END specify the portion of the current buffer to be copied."
       (save-excursion
        (insert-buffer-substring oldbuf start end)))))
 \f
-(defvar mark-even-if-inactive nil
-  "*Non-nil means you can use the mark even when inactive.
-This option makes a difference in Transient Mark mode.
-When the option is non-nil, deactivation of the mark
-turns off region highlighting, but commands that use the mark
-behave as if the mark were still active.")
-
 (put 'mark-inactive 'error-conditions '(mark-inactive error))
 (put 'mark-inactive 'error-message "The mark is not active now")
 
@@ -1569,42 +1689,87 @@ It is the column where point was
 at the start of current run of vertical motion commands.
 When the `track-eol' feature is doing its job, the value is 9999.")
 
+(defvar line-move-ignore-invisible nil
+  "*Non-nil means \\[next-line] and \\[previous-line] ignore invisible lines.
+Outline mode sets this.")
+
+;; This is the guts of next-line and previous-line.
+;; Arg says how many lines to move.
 (defun line-move (arg)
-  (if (not (or (eq last-command 'next-line)
-              (eq last-command 'previous-line)))
-      (setq temporary-goal-column
-           (if (and track-eol (eolp)
-                    ;; Don't count beg of empty line as end of line
-                    ;; unless we just did explicit end-of-line.
-                    (or (not (bolp)) (eq last-command 'end-of-line)))
-               9999
-             (current-column))))
-  (if (not (integerp selective-display))
-      (or (if (> arg 0)
-             (progn (if (> arg 1) (forward-line (1- arg)))
-                    ;; This way of moving forward ARG lines
-                    ;; verifies that we have a newline after the last one.
-                    ;; It doesn't get confused by intangible text.
-                    (end-of-line)
-                    (zerop (forward-line 1)))
-           (and (zerop (forward-line arg))
-                (bolp)))
-         (signal (if (< arg 0)
-                     'beginning-of-buffer
-                   'end-of-buffer)
-                 nil))
-    ;; Move by arg lines, but ignore invisible ones.
-    (while (> arg 0)
-      (end-of-line)
-      (and (zerop (vertical-motion 1))
-          (signal 'end-of-buffer nil))
-      (setq arg (1- arg)))
-    (while (< arg 0)
-      (beginning-of-line)
-      (and (zerop (vertical-motion -1))
-          (signal 'beginning-of-buffer nil))
-      (setq arg (1+ arg))))
-  (move-to-column (or goal-column temporary-goal-column))
+  ;; Don't run any point-motion hooks, and disregard intangibility,
+  ;; for intermediate positions.
+  (let ((inhibit-point-motion-hooks t)
+       (opoint (point))
+       new)
+    (unwind-protect
+       (progn
+         (if (not (or (eq last-command 'next-line)
+                      (eq last-command 'previous-line)))
+             (setq temporary-goal-column
+                   (if (and track-eol (eolp)
+                            ;; Don't count beg of empty line as end of line
+                            ;; unless we just did explicit end-of-line.
+                            (or (not (bolp)) (eq last-command 'end-of-line)))
+                       9999
+                     (current-column))))
+         (if (and (not (integerp selective-display))
+                  (not line-move-ignore-invisible))
+             ;; Use just newline characters.
+             (or (if (> arg 0)
+                     (progn (if (> arg 1) (forward-line (1- arg)))
+                            ;; This way of moving forward ARG lines
+                            ;; verifies that we have a newline after the last one.
+                            ;; It doesn't get confused by intangible text.
+                            (end-of-line)
+                            (zerop (forward-line 1)))
+                   (and (zerop (forward-line arg))
+                        (bolp)))
+                 (signal (if (< arg 0)
+                             'beginning-of-buffer
+                           'end-of-buffer)
+                         nil))
+           ;; Move by arg lines, but ignore invisible ones.
+           (while (> arg 0)
+             (end-of-line)
+             (and (zerop (vertical-motion 1))
+                  (signal 'end-of-buffer nil))
+             ;; If the following character is currently invisible,
+             ;; skip all characters with that same `invisible' property value.
+             (while (and (not (eobp))
+                         (let ((prop
+                                (get-char-property (point) 'invisible)))
+                           (if (eq buffer-invisibility-spec t)
+                               prop
+                             (or (memq prop buffer-invisibility-spec)
+                                 (assq prop buffer-invisibility-spec)))))
+               (if (get-text-property (point) 'invisible)
+                   (goto-char (next-single-property-change (point) 'invisible))
+                 (goto-char (next-overlay-change (point)))))
+             (setq arg (1- arg)))
+           (while (< arg 0)
+             (beginning-of-line)
+             (and (zerop (vertical-motion -1))
+                  (signal 'beginning-of-buffer nil))
+             (while (and (not (bobp))
+                         (let ((prop
+                                (get-char-property (1- (point)) 'invisible)))
+                           (if (eq buffer-invisibility-spec t)
+                               prop
+                             (or (memq prop buffer-invisibility-spec)
+                                 (assq prop buffer-invisibility-spec)))))
+               (if (get-text-property (1- (point)) 'invisible)
+                   (goto-char (previous-single-property-change (point) 'invisible))
+                 (goto-char (previous-overlay-change (point)))))
+             (setq arg (1+ arg))))
+         (move-to-column (or goal-column temporary-goal-column)))
+      ;; Remember where we moved to, go back home,
+      ;; then do the motion over again
+      ;; in just one step, with intangibility and point-motion hooks
+      ;; enabled this time.
+      (setq new (point))
+      (goto-char opoint)
+      (setq inhibit-point-motion-hooks nil)
+      (goto-char new)))
   nil)
 
 ;;; Many people have said they rarely use this feature, and often type
@@ -1880,7 +2045,7 @@ can set the value for a particular mode using that mode's hook.")
 (make-variable-buffer-local 'comment-column)
 
 (defconst comment-start nil
-  "*String to insert to start a new comment, or nil if no comment syntax defined.")
+  "*String to insert to start a new comment, or nil if no comment syntax.")
 
 (defconst comment-start-skip nil
   "*Regexp to match the start of a comment plus everything up to its body.
@@ -1902,47 +2067,62 @@ the comment's starting delimiter.")
 This function is called with no args with point at the beginning of
 the comment's starting delimiter.")
 
+(defconst block-comment-start nil
+  "*String to insert to start a new comment on a line by itself.
+If nil, use `comment-start' instead.
+Note that the regular expression `comment-start-skip' should skip this string
+as well as the `comment-start' string.")
+
+(defconst block-comment-end nil
+  "*String to insert to end a new comment on a line by itself.
+Should be an empty string if comments are terminated by end-of-line.
+If nil, use `comment-end' instead.")
+
 (defun indent-for-comment ()
   "Indent this line's comment to comment column, or insert an empty comment."
   (interactive "*")
-  (beginning-of-line 1)
-  (if (null comment-start)
-      (error "No comment syntax defined")
-    (let* ((eolpos (save-excursion (end-of-line) (point)))
-          cpos indent begpos)
-      (if (re-search-forward comment-start-skip eolpos 'move)
-         (progn (setq cpos (point-marker))
-                ;; Find the start of the comment delimiter.
-                ;; If there were paren-pairs in comment-start-skip,
-                ;; position at the end of the first pair.
-                (if (match-end 1)
-                    (goto-char (match-end 1))
-                  ;; If comment-start-skip matched a string with
-                  ;; internal whitespace (not final whitespace) then
-                  ;; the delimiter start at the end of that
-                  ;; whitespace.  Otherwise, it starts at the
-                  ;; beginning of what was matched.
-                  (skip-syntax-backward " " (match-beginning 0))
-                  (skip-syntax-backward "^ " (match-beginning 0)))))
-      (setq begpos (point))
-      ;; Compute desired indent.
-      (if (= (current-column)
-            (setq indent (if comment-indent-hook
-                             (funcall comment-indent-hook)
-                           (funcall comment-indent-function))))
-         (goto-char begpos)
-       ;; If that's different from current, change it.
-       (skip-chars-backward " \t")
-       (delete-region (point) begpos)
-       (indent-to indent))
-      ;; An existing comment?
-      (if cpos 
-         (progn (goto-char cpos)
-                (set-marker cpos nil))
-       ;; No, insert one.
-       (insert comment-start)
-       (save-excursion
-         (insert comment-end))))))
+  (let* ((empty (save-excursion (beginning-of-line)
+                               (looking-at "[ \t]*$")))
+        (starter (or (and empty block-comment-start) comment-start))
+        (ender (or (and empty block-comment-end) comment-end)))
+    (if (null starter)
+       (error "No comment syntax defined")
+      (let* ((eolpos (save-excursion (end-of-line) (point)))
+            cpos indent begpos)
+       (beginning-of-line)
+       (if (re-search-forward comment-start-skip eolpos 'move)
+           (progn (setq cpos (point-marker))
+                  ;; Find the start of the comment delimiter.
+                  ;; If there were paren-pairs in comment-start-skip,
+                  ;; position at the end of the first pair.
+                  (if (match-end 1)
+                      (goto-char (match-end 1))
+                    ;; If comment-start-skip matched a string with
+                    ;; internal whitespace (not final whitespace) then
+                    ;; the delimiter start at the end of that
+                    ;; whitespace.  Otherwise, it starts at the
+                    ;; beginning of what was matched.
+                    (skip-syntax-backward " " (match-beginning 0))
+                    (skip-syntax-backward "^ " (match-beginning 0)))))
+       (setq begpos (point))
+       ;; Compute desired indent.
+       (if (= (current-column)
+              (setq indent (if comment-indent-hook
+                               (funcall comment-indent-hook)
+                             (funcall comment-indent-function))))
+           (goto-char begpos)
+         ;; If that's different from current, change it.
+         (skip-chars-backward " \t")
+         (delete-region (point) begpos)
+         (indent-to indent))
+       ;; An existing comment?
+       (if cpos 
+           (progn (goto-char cpos)
+                  (set-marker cpos nil))
+         ;; No, insert one.
+         (insert starter)
+         (save-excursion
+           (insert ender)))))))
 
 (defun set-comment-column (arg)
   "Set the comment column based on point.
@@ -2230,8 +2410,7 @@ automatically breaks the line at a previous space."
                       (> (prefix-numeric-value arg) 0))
                   'do-auto-fill
                   nil))
-    ;; update mode-line
-    (set-buffer-modified-p (buffer-modified-p))))
+    (force-mode-line-update)))
 
 ;; This holds a document string used to document auto-fill-mode.
 (defun auto-fill-function ()
@@ -2282,20 +2461,19 @@ unless optional argument SOFT is non-nil."
              ;; Set WIN to the pos of the comment-start.
              ;; But if the comment is empty, look at preceding lines
              ;; to find one that has a nonempty comment.
-             (let ((win (match-beginning 0)))
+
+             ;; If comment-start-skip contains a \(...\) pair,
+             ;; the real comment delimiter starts at the end of that pair.
+             (let ((win (or (match-end 1) (match-beginning 0))))
                (while (and (eolp) (not (bobp))
                            (let (opoint)
                              (beginning-of-line)
                              (setq opoint (point))
                              (forward-line -1)
                              (re-search-forward comment-start-skip opoint t)))
-                 (setq win (match-beginning 0)))
+                 (setq win (or (match-end 1) (match-beginning 0))))
                ;; Indent this line like what we found.
                (goto-char win)
-               ;; If comment-start-skip contains a \(...\) pair,
-               ;; the real comment delimiter starts at the end of that pair.
-               (if (match-end 1)
-                   (goto-char (match-end 1)))
                (setq comcol (current-column))
                (setq comstart
                      (buffer-substring (point) (match-end 0)))))))
@@ -2571,7 +2749,8 @@ it were the arg to `interactive' (which see) to interactively read the value."
 \f
 ;; Define the major mode for lists of completions.
 
-(defvar completion-list-mode-map nil)
+(defvar completion-list-mode-map nil
+  "Local map for completion list buffers.")
 (or completion-list-mode-map
     (let ((map (make-sparse-keymap)))
       (define-key map [mouse-2] 'mouse-choose-completion)
@@ -2585,13 +2764,17 @@ it were the arg to `interactive' (which see) to interactively read the value."
 ;; Completion mode is suitable only for specially formatted data.
 (put 'completion-list-mode 'mode-class 'special)
 
-;; Record the buffer that was current when the completion list was requested.
-;; Initial value is nil to avoid some compiler warnings.
-(defvar completion-reference-buffer nil)
+(defvar completion-reference-buffer nil
+  "Record the buffer that was current when the completion list was requested.
+This is a local variable in the completion list buffer.
+Initial value is nil to avoid some compiler warnings.")
 
-;; This records the length of the text at the beginning of the buffer
-;; which was not included in the completion.
-(defvar completion-base-size nil)
+(defvar completion-base-size nil
+  "Number of chars at beginning of minibuffer not involved in completion.
+This is a local variable in the completion list buffer
+but it talks about the buffer in `completion-reference-buffer'.
+If this is nil, it means to compare text to determine which part
+of the tail end of the buffer's text is involved in completion.")
 
 (defun delete-completion-window ()
   "Delete the completion list window.
@@ -2638,7 +2821,7 @@ WIth prefix argument N, move N items (negative N means move backward)."
     (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
        (setq end (point) beg (1+ (point))))
     (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
-       (setq end (1- (point)) beg(point)))
+       (setq end (1- (point)) beg (point)))
     (if (null beg)
        (error "No completion here"))
     (setq beg (previous-single-property-change beg 'mouse-face))
@@ -2673,13 +2856,17 @@ WIth prefix argument N, move N items (negative N means move backward)."
       (forward-char 1))
     (delete-char len)))
 
+;; Switch to BUFFER and insert the completion choice CHOICE.
+;; BASE-SIZE, if non-nil, says how many characters of BUFFER's text
+;; to keep.  If it is nil, use choose-completion-delete-max-match instead.
 (defun choose-completion-string (choice &optional buffer base-size)
   (let ((buffer (or buffer completion-reference-buffer)))
     ;; If BUFFER is a minibuffer, barf unless it's the currently
     ;; active minibuffer.
     (if (and (string-match "\\` \\*Minibuf-[0-9]+\\*\\'" (buffer-name buffer))
-            (or (not (minibuffer-window-active-p (minibuffer-window)))
-                (not (equal buffer (window-buffer (minibuffer-window))))))
+            (or (not (active-minibuffer-window))
+                (not (equal buffer
+                            (window-buffer (active-minibuffer-window))))))
        (error "Minibuffer is not active for completion")
       ;; Insert the completion into the buffer where completion was requested.
       (set-buffer buffer)
@@ -2712,7 +2899,15 @@ Use \\<completion-list-mode-map>\\[mouse-choose-completion] to select one\
   (setq completion-base-size nil)
   (run-hooks 'completion-list-mode-hook))
 
-(defvar completion-fixup-function nil)
+(defvar completion-fixup-function nil
+  "A function to customize how completions are identified in completion lists.
+`completion-setup-function' calls this function with no arguments
+each time it has found what it thinks is one completion.
+Point is at the end of the completion in the completion list buffer.
+If this function moves point, it can alter the end of that completion.")
+
+;; 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 ()
   (save-excursion
@@ -2721,6 +2916,9 @@ Use \\<completion-list-mode-map>\\[mouse-choose-completion] to select one\
       (completion-list-mode)
       (make-local-variable 'completion-reference-buffer)
       (setq completion-reference-buffer mainbuf)
+;;; The value 0 is right in most cases, but not for file name completion.
+;;; so this has to be turned off.
+;;;      (setq completion-base-size 0)
       (goto-char (point-min))
       (if window-system
          (insert (substitute-command-keys
@@ -2756,6 +2954,60 @@ select the completion near point.\n\n"))
   (search-forward "\n\n")
   (forward-line 1))
 \f
+;; Support keyboard commands to turn on various modifiers.
+
+;; These functions -- which are not commands -- each add one modifier
+;; to the following event.
+
+(defun event-apply-alt-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'alt 22 "A-")))
+(defun event-apply-super-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'super 23 "s-")))
+(defun event-apply-hyper-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'hyper 24 "H-")))
+(defun event-apply-shift-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'shift 25 "S-")))
+(defun event-apply-control-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'control 26 "C-")))
+(defun event-apply-meta-modifier (ignore-prompt)
+  (vector (event-apply-modifier (read-event) 'meta 27 "M-")))
+
+(defun event-apply-modifier (event symbol lshiftby prefix)
+  "Apply a modifier flag to event EVENT.
+SYMBOL is the name of this modifier, as a symbol.
+LSHIFTBY is the numeric value of this modifier, in keyboard events.
+PREFIX is the string that represents this modifier in an event type symbol."
+  (if (numberp event)
+      (cond ((eq symbol 'control)
+            (if (and (<= (downcase event) ?z)
+                     (>= (downcase event) ?a))
+                (- (downcase event) ?a -1)
+              (if (and (<= (downcase event) ?Z)
+                       (>= (downcase event) ?A))
+                  (- (downcase event) ?A -1)
+                (logior (lsh 1 lshiftby) event))))
+           ((eq symbol 'shift)
+            (if (and (<= (downcase event) ?z)
+                     (>= (downcase event) ?a))
+                (upcase event)
+              (logior (lsh 1 lshiftby) event)))
+           (t
+            (logior (lsh 1 lshiftby) event)))
+    (if (memq symbol (event-modifiers event))
+       event
+      (let ((event-type (if (symbolp event) event (car event))))
+       (setq event-type (intern (concat prefix (symbol-name event-type))))
+       (if (symbolp event)
+           event-type
+         (cons event-type (cdr event)))))))
+
+(define-key function-key-map [?\C-x ?@ ?h] 'event-apply-hyper-modifier)
+(define-key function-key-map [?\C-x ?@ ?s] 'event-apply-super-modifier)
+(define-key function-key-map [?\C-x ?@ ?m] 'event-apply-meta-modifier)
+(define-key function-key-map [?\C-x ?@ ?a] 'event-apply-alt-modifier)
+(define-key function-key-map [?\C-x ?@ ?S] 'event-apply-shift-modifier)
+(define-key function-key-map [?\C-x ?@ ?c] 'event-apply-control-modifier)
+\f
 ;;;; Keypad support.
 
 ;;; Make the keypad keys act like ordinary typing keys.  If people add