]> code.delx.au - gnu-emacs/blobdiff - lisp/simple.el
entered into RCS
[gnu-emacs] / lisp / simple.el
index f008094a659418cef9dfaccc867f76d347b5349f..982bd78047d8ff08e2be4db7c20bfaee840bc0f2 100644 (file)
@@ -1,11 +1,12 @@
-;; Basic editing commands for Emacs
-;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+;;; simple.el --- basic editing commands for Emacs
+
+;; Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -17,6 +18,7 @@
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Code:
 
 (defun open-line (arg)
   "Insert a newline and leave point before it.  If there is a fill
@@ -54,6 +56,7 @@ You may also type up to 3 octal digits, to insert a character with that code"
 
 (defun delete-indentation (&optional arg)
   "Join this line to previous and fix up whitespace at join.
+If there is a fill prefix, delete it from the beginning of this line.
 With argument, join this line to following line."
   (interactive "*P")
   (beginning-of-line)
@@ -61,6 +64,13 @@ With argument, join this line to following line."
   (if (eq (preceding-char) ?\n)
       (progn
        (delete-region (point) (1- (point)))
+       ;; If the second line started with the fill prefix,
+       ;; delete the prefix.
+       (if (and fill-prefix
+                (string= fill-prefix
+                         (buffer-substring (point)
+                                           (+ (point) (length fill-prefix)))))
+           (delete-region (point) (+ (point) (length fill-prefix))))
        (fixup-whitespace))))
 
 (defun fixup-whitespace ()
@@ -99,12 +109,14 @@ On nonblank line, delete all blank lines that follow it."
     (save-excursion
       (beginning-of-line)
       (setq thisblank (looking-at "[ \t]*$"))
+      ;; Set singleblank if there is just one blank line here.
       (setq singleblank
            (and thisblank
                 (not (looking-at "[ \t]*\n[ \t]*$"))
                 (or (bobp)
                     (progn (forward-line -1)
                            (not (looking-at "[ \t]*$")))))))
+    ;; Delete preceding blank lines, and this one too if it's the only one.
     (if thisblank
        (progn
          (beginning-of-line)
@@ -113,6 +125,8 @@ On nonblank line, delete all blank lines that follow it."
                         (if (re-search-backward "[^ \t\n]" nil t)
                             (progn (forward-line 1) (point))
                           (point-min)))))
+    ;; Delete following blank lines, unless the current line is blank
+    ;; and there are no following blank lines.
     (if (not (and thisblank singleblank))
        (save-excursion
          (end-of-line)
@@ -120,7 +134,11 @@ On nonblank line, delete all blank lines that follow it."
          (delete-region (point)
                         (if (re-search-forward "[^ \t\n]" nil t)
                             (progn (beginning-of-line) (point))
-                          (point-max)))))))
+                          (point-max)))))
+    ;; Handle the special case where point is followed by newline and eob.
+    ;; Delete the line, leaving point at eob.
+    (if (looking-at "^[ \t]*\n\\'")
+       (delete-region (point) (point-max)))))
 
 (defun back-to-indentation ()
   "Move point to the first non-whitespace character on this line."
@@ -136,7 +154,7 @@ In some text modes, where TAB inserts a tab, this indents to the
 specified left-margin column."
   (interactive "*")
   (delete-region (point) (progn (skip-chars-backward " \t") (point)))
-  (insert ?\n)
+  (newline)
   (indent-according-to-mode))
 
 (defun reindent-then-newline-and-indent ()
@@ -150,7 +168,7 @@ specified left-margin column."
   (save-excursion
     (delete-region (point) (progn (skip-chars-backward " \t") (point)))
     (indent-according-to-mode))
-  (insert ?\n)
+  (newline)
   (indent-according-to-mode))
 
 ;; Internal subroutine of delete-char
@@ -228,13 +246,23 @@ Don't use this in Lisp programs!
                           (/ (buffer-size) 10))
                      (/ (* (buffer-size) (prefix-numeric-value arg)) 10)))
               (point-max)))
+  ;; If we went to a place in the middle of the buffer,
+  ;; adjust it to the beginning of a line.
   (if arg (forward-line 1)
-    ;; Scroll to put point near bottom--show nearly maximum amount of text,
-    ;; but leave room to add something.
-    (recenter -3)))
+    ;; If the end of the buffer is not already on the screen,
+    ;; then scroll specially to put it near, but not at, the bottom.
+    (if (let ((old-point (point)))
+         (save-excursion
+                   (goto-char (window-start))
+                   (vertical-motion (window-height))
+                   (< (point) old-point)))
+       (recenter -3))))
 
 (defun mark-whole-buffer ()
-  "Put point at beginning and mark at end of buffer."
+  "Put point at beginning and mark at end of buffer.
+You probably should not use this function in Lisp programs;
+it is usually a mistake for a Lisp function to use any subroutine
+that uses or sets the mark."
   (interactive)
   (push-mark (point))
   (push-mark (point-max))
@@ -314,7 +342,7 @@ Other major modes are defined by comparison with this one."
 ;; for the sake of completion of names like eval-region, eval-current-buffer.
 (defun eval-expression (expression)
   "Evaluate EXPRESSION and print value in minibuffer.
-Value is also consed on to front of variable  values  's value."
+Value is also consed on to front of the variable `values'."
   (interactive "xEval: ")
   (setq values (cons (eval expression) values))
   (prin1 (car values) t))
@@ -330,59 +358,111 @@ the minibuffer, then read and evaluate the result."
        (setq command-history (cons command command-history)))
     (eval command)))
 
-;; (defvar repeat-complex-command nil)
-
-(defvar repeat-complex-command-map (copy-keymap minibuffer-local-map))
-(define-key repeat-complex-command-map "\ep" 'previous-complex-command)
-(define-key repeat-complex-command-map "\en" 'next-complex-command)
-(defun repeat-complex-command (repeat-complex-command-arg)
+(defun repeat-complex-command (arg)
   "Edit and re-evaluate last complex command, or ARGth from last.
 A complex command is one which used the minibuffer.
 The command is placed in the minibuffer as a Lisp form for editing.
 The result is executed, repeating the command as changed.
 If the command has been changed or is not the most recent previous command
 it is added to the front of the command history.
-Whilst editing the command, the following commands are available:
-\\{repeat-complex-command-map}"
+You can use the minibuffer history commands \\<minibuffer-local-map>\\[next-history-element] and \\[previous-history-element]
+to get different commands to edit and resubmit."
   (interactive "p")
-  (let ((elt (nth (1- repeat-complex-command-arg) command-history))
-       (repeat-complex-command-flag t)
+  (let ((elt (nth (1- arg) command-history))
+       (minibuffer-history-position arg)
+       (minibuffer-history-sexp-flag t)
        newcmd)
     (if elt
-       (progn
+       (let ((minibuffer-history-variable ' command-history))
          (setq newcmd (read-from-minibuffer "Redo: "
                                             (prin1-to-string elt)
-                                            repeat-complex-command-map
-                                            t))
+                                            minibuffer-local-map
+                                            t
+                                            (cons 'command-history
+                                                  arg)))
          ;; If command to be redone does not match front of history,
          ;; add it to the history.
          (or (equal newcmd (car command-history))
              (setq command-history (cons newcmd command-history)))
          (eval newcmd))
       (ding))))
-
-(defun next-complex-command (n)
-  "Inserts the next element of `command-history' into the minibuffer."
+\f
+(defvar minibuffer-history nil)
+(defvar minibuffer-history-sexp-flag nil)
+(setq minibuffer-history-variable 'minibuffer-history)
+(setq minibuffer-history-position nil)
+
+(mapcar
+ (function (lambda (key-and-command)
+            (mapcar
+             (function (lambda (keymap)
+                         (define-key (symbol-value keymap)
+                           (car key-and-command)
+                           (cdr key-and-command))))
+             '(minibuffer-local-map
+               minibuffer-local-ns-map
+               minibuffer-local-completion-map
+               minibuffer-local-must-match-map))))
+ '(("\en" . next-history-element) ([next] . next-history-element)
+   ("\ep" . previous-history-element) ([prior] . previous-history-element)
+   ("\er" . previous-matching-history-element)
+   ("\es" . next-matching-history-element)))
+
+(put 'previous-matching-history-element 'enable-recursive-minibuffers t)
+(defun previous-matching-history-element (regexp n)
+  (interactive "sPrevious element matching (regexp): \np")
+  (let ((history (symbol-value minibuffer-history-variable))
+       prevpos
+       (pos minibuffer-history-position))
+    (while (/= n 0)
+      (setq prevpos pos)
+      (setq pos (min (max 1 (+ pos (if (< n 0) -1 1))) (length history)))
+      (if (= pos prevpos)
+         (error (if (= pos 1)
+                    "No later matching history item"
+                  "No earlier matching history item")))
+      (if (string-match regexp
+                       (if minibuffer-history-sexp-flag
+                           (prin1-to-string (nth (1- pos) history))
+                         (nth (1- pos) history)))
+         (setq n (+ n (if (< n 0) -1 1)))))
+    (setq minibuffer-history-position pos)
+    (erase-buffer)
+    (let ((elt (nth (1- pos) history)))
+      (insert (if minibuffer-history-sexp-flag
+                 (prin1-to-string elt)
+               elt)))
+      (goto-char (point-min))))
+
+(put 'next-matching-history-element 'enable-recursive-minibuffers t)
+(defun next-matching-history-element (regexp n)
+  (interactive "sNext element matching (regexp): \np")
+  (previous-matching-history-element regexp (- n)))
+
+(defun next-history-element (n)
+  "Insert the next element of the minibuffer history into the minibuffer."
   (interactive "p")
-  (let ((narg (min (max 1 (- repeat-complex-command-arg n))
-                  (length command-history))))
-    (if (= repeat-complex-command-arg narg)
-       (error (if (= repeat-complex-command-arg 1)
-                  "No following item in command history"
-                "No preceding item in command history"))
+  (let ((narg (min (max 1 (- minibuffer-history-position n))
+                  (length (symbol-value minibuffer-history-variable)))))
+    (if (= minibuffer-history-position narg)
+       (error (if (= minibuffer-history-position 1)
+                  "End of history; no next item"
+                "Beginning of history; no preceding item"))
       (erase-buffer)
-      (setq repeat-complex-command-arg narg)
-      (insert (prin1-to-string (nth (1- repeat-complex-command-arg)
-                                   command-history)))
+      (setq minibuffer-history-position narg)
+      (let ((elt (nth (1- minibuffer-history-position)
+                     (symbol-value minibuffer-history-variable))))
+       (insert
+        (if minibuffer-history-sexp-flag
+            (prin1-to-string elt)
+          elt)))
       (goto-char (point-min)))))
 
-(defun previous-complex-command (n)
+(defun previous-history-element (n)
   "Inserts the previous element of `command-history' into the minibuffer."
   (interactive "p")
-  (if repeat-complex-command-flag
-      (next-complex-command (- n))
-    (repeat-complex-command 1)))
-
+  (next-history-element (- n)))
+\f
 (defun goto-line (arg)
   "Goto line ARG, counting from line 1 at beginning of buffer."
   (interactive "NGoto line: ")
@@ -402,7 +482,8 @@ Repeat this command to undo more changes.
 A numeric argument serves as a repeat count."
   (interactive "*p")
   (let ((modified (buffer-modified-p)))
-    (message "Undo!")
+    (or (eq (selected-window) (minibuffer-window))
+       (message "Undo!"))
     (or (eq last-command 'undo)
        (progn (undo-start)
               (undo-more 1)))
@@ -589,12 +670,12 @@ Repeating \\[universal-argument] without digits or minus sign
   (interactive nil)
   (let ((factor 4)
        key)
-    (describe-arg (list factor) 1)
-    (setq key (read-key-sequence nil))
+;;    (describe-arg (list factor) 1)
+    (setq key (read-key-sequence nil t))
     (while (equal (key-binding key) 'universal-argument)
       (setq factor (* 4 factor))
-      (describe-arg (list factor) 1)
-      (setq key (read-key-sequence nil)))
+;;      (describe-arg (list factor) 1)
+      (setq key (read-key-sequence nil t)))
     (prefix-arg-internal key factor nil)))
 
 (defun prefix-arg-internal (key factor value)
@@ -603,19 +684,19 @@ Repeating \\[universal-argument] without digits or minus sign
        (setq sign -1 value (- value)))
     (if (eq value '-)
        (setq sign -1 value nil))
-    (describe-arg value sign)
+;;    (describe-arg value sign)
     (while (equal key "-")
       (setq sign (- sign) factor nil)
-      (describe-arg value sign)
-      (setq key (read-key-sequence nil)))
+;;      (describe-arg value sign)
+      (setq key (read-key-sequence nil t)))
     (while (and (= (length key) 1)
                (not (string< key "0"))
                (not (string< "9" key)))
       (setq value (+ (* (if (numberp value) value 0) 10)
                     (- (aref key 0) ?0))
            factor nil)
-      (describe-arg value sign)
-      (setq key (read-key-sequence nil)))
+;;      (describe-arg value sign)
+      (setq key (read-key-sequence nil t)))
     (setq prefix-arg
          (cond (factor (list factor))
                ((numberp value) (* value sign))
@@ -625,7 +706,7 @@ Repeating \\[universal-argument] without digits or minus sign
     (if (eq (key-binding key) 'universal-argument)
        (progn
          (describe-arg value sign)
-         (setq key (read-key-sequence nil))))
+         (setq key (read-key-sequence nil t))))
     (if (= (length key) 1)
        ;; Make sure self-insert-command finds the proper character;
        ;; unread the character and let the command loop process it.
@@ -686,10 +767,53 @@ a number counts as a prefix arg."
                     (end-of-line)))
                 (point))))
 \f
-;;;; The kill ring
+;;;; Window system cut and paste hooks.
+
+(defvar interprogram-cut-function nil
+  "Function to call to make a killed region available to other programs.
+
+Most window systems provide some sort of facility for cutting and
+pasting text between the windows of different programs.  On startup,
+this variable is set to a function which emacs will call whenever text
+is put in the kill ring to make the new kill available to other
+programs.
+
+The function takes one argument, TEXT, which is a string containing
+the text which should be made available.")
+
+(defvar interprogram-paste-function nil
+  "Function to call to get text cut from other programs.
+
+Most window systems provide some sort of facility for cutting and
+pasting text between the windows of different programs.  On startup,
+this variable is set to a function which emacs will call to obtain
+text that other programs have provided for pasting.
+
+The function should be called with no arguments.  If the function
+returns nil, then no other program has provided such text, and the top
+of the Emacs kill ring should be used.  If the function returns a
+string, that string should be put in the kill ring as the latest kill.
+
+Note that the function should return a string only if a program other
+than Emacs has provided a string for pasting; if Emacs provided the
+most recent string, the function should return nil.  If it is
+difficult to tell whether Emacs or some other program provided the
+current string, it is probably good enough to return nil if the string
+is equal (according to `string=') to the last text Emacs provided.")
+
+
+\f
+;;;; The kill ring data structure.
 
 (defvar kill-ring nil
-  "List of killed text sequences.")
+  "List of killed text sequences.
+Since the kill ring is supposed to interact nicely with cut-and-paste
+facilities offered by window systems, use of this variable should
+interact nicely with `interprogram-cut-function' and
+`interprogram-paste-function'.  The functions `kill-new',
+`kill-append', and `current-kill' are supposed to implement this
+interaction; you may want to use them instead of manipulating the kill
+ring directly.")
 
 (defconst kill-ring-max 30
   "*Maximum length of kill ring before oldest elements are thrown away.")
@@ -697,11 +821,60 @@ a number counts as a prefix arg."
 (defvar kill-ring-yank-pointer nil
   "The tail of the kill ring whose car is the last thing yanked.")
 
+(defun kill-new (string)
+  "Make STRING the latest kill in the kill ring.
+Set the kill-ring-yank pointer to point to it.
+If `interprogram-cut-function' is non-nil, apply it to STRING."
+  (setq kill-ring (cons string kill-ring))
+  (if (> (length kill-ring) kill-ring-max)
+      (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
+  (setq kill-ring-yank-pointer kill-ring)
+  (if interprogram-cut-function
+      (funcall interprogram-cut-function string)))
+
 (defun kill-append (string before-p)
+  "Append STRING to the end of the latest kill in the kill ring.
+If BEFORE-P is non-nil, prepend STRING to the kill.
+If 'interprogram-cut-function' is set, pass the resulting kill to
+it."
   (setcar kill-ring
          (if before-p
              (concat string (car kill-ring))
-             (concat (car kill-ring) string))))
+           (concat (car kill-ring) string)))
+  (if interprogram-cut-function
+      (funcall interprogram-cut-function (car kill-ring))))
+
+(defun current-kill (n &optional do-not-move)
+  "Rotate the yanking point by N places, and then return that kill.
+If N is zero, `interprogram-paste-function' is set, and calling it
+returns a string, then that string is added to the front of the
+kill ring and returned as the latest kill.
+If optional arg DO-NOT-MOVE is non-nil, then don't actually move the 
+yanking point; just return the Nth kill forward."
+  (let ((interprogram-paste (and (= n 0)
+                                interprogram-paste-function
+                                (funcall interprogram-paste-function))))
+    (if interprogram-paste
+       (progn
+         ;; Disable the interprogram cut function when we add the new
+         ;; text to the kill ring, so Emacs doesn't try to own the
+         ;; selection, with identical text.
+         (let ((interprogram-cut-function nil))
+           (kill-new interprogram-paste))
+         interprogram-paste)
+      (or kill-ring (error "Kill ring is empty"))
+      (let* ((length (length kill-ring))
+            (ARGth-kill-element
+             (nthcdr (% (+ n (- length (length kill-ring-yank-pointer)))
+                        length)
+                     kill-ring)))
+       (or do-not-move
+           (setq kill-ring-yank-pointer ARGth-kill-element))
+       (car ARGth-kill-element)))))
+
+
+\f
+;;;; Commands for manipulating the kill ring.
 
 (defun kill-region (beg end)
   "Kill between point and mark.
@@ -717,55 +890,53 @@ If the previous command was also a kill command,
 the text killed this time appends to the text killed last time
 to make one entry in the kill ring."
   (interactive "r")
-  (if (and (not (eq buffer-undo-list t))
-          (not (eq last-command 'kill-region))
-          (not (eq beg end))
-          (not buffer-read-only))
-      ;; Don't let the undo list be truncated before we can even access it.
-      (let ((undo-high-threshold (+ (- (max beg end) (min beg end)) 100)))
-       (delete-region beg end)
-       ;; Take the same string recorded for undo
-       ;; and put it in the kill-ring.
-       (setq kill-ring (cons (car (car buffer-undo-list)) kill-ring))
-       (if (> (length kill-ring) kill-ring-max)
-           (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
-       (setq this-command 'kill-region)
-       (setq kill-ring-yank-pointer kill-ring))
+  (cond
+   (buffer-read-only
+    (copy-region-as-kill beg end))
+   ((not (or (eq buffer-undo-list t)
+            (eq last-command 'kill-region)
+            (eq beg end)))
+    ;; Don't let the undo list be truncated before we can even access it.
+    (let ((undo-strong-limit (+ (- (max beg end) (min beg end)) 100)))
+      (delete-region beg end)
+      ;; Take the same string recorded for undo
+      ;; and put it in the kill-ring.
+      (kill-new (car (car buffer-undo-list)))
+      (setq this-command 'kill-region)))
+   (t
     (copy-region-as-kill beg end)
-    (or buffer-read-only (delete-region beg end))))
-
-(defvar interprogram-cut-function nil
-  "Function to call to make a killed region available to other programs.
-
-Most window systems provide some sort of facility for cutting and
-pasting text between the windows of different programs.  On startup,
-this variable is set to a function which emacs will call to make the
-most recently killed text available to other programs.
-
-The function takes one argument, TEXT, which is a string containing
-the text which should be made available.")
+    (delete-region beg end))))
 
 (defun copy-region-as-kill (beg end)
   "Save the region as if killed, but don't kill it.
-If `x-select-kill' is non-nil, also save the text for X cut and paste."
+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))
-    (setq kill-ring (cons (buffer-substring beg end) kill-ring))
-    (if (> (length kill-ring) kill-ring-max)
-       (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
-  (if interprogram-cut-function
-      (funcall interprogram-cut-function (car kill-ring)))
-  (setq this-command 'kill-region
-       kill-ring-yank-pointer kill-ring)
+    (kill-new (buffer-substring beg end)))
+  (setq this-command 'kill-region)
   nil)
 
 (defun kill-ring-save (beg end)
   "Save the region as if killed, but don't kill it."
   (interactive "r")
   (copy-region-as-kill beg end)
-  (message "%d characters copied to kill ring"
-          (- (max beg end) (min beg end))))
+  (if (interactive-p)
+      (save-excursion
+       (let ((other-end (if (= (point) beg) end beg)))
+         (if (pos-visible-in-window-p other-end (selected-window))
+             (progn
+               (goto-char other-end)
+               (sit-for 1))
+           (let* ((killed-text (current-kill 0))
+                  (message-len (min (length killed-text) 40)))
+             (if (= (point) beg)
+                 ;; Don't say "killed"; that is misleading.
+                 (message "Saved text until \"%s\""
+                         (substring killed-text (- message-len)))
+               (message "Saved text from \"%s\""
+                       (substring killed-text 0 message-len)))))))))
 
 (defun append-next-kill ()
   "Cause following command, if kill, to append to previous kill."
@@ -776,17 +947,6 @@ If `x-select-kill' is non-nil, also save the text for X cut and paste."
        (message "If the next command is a kill, it will append"))
     (setq last-command 'kill-region)))
 
-(defun rotate-yank-pointer (arg)
-  "Rotate the yanking point in the kill ring."
-  (interactive "p")
-  (let ((length (length kill-ring)))
-    (if (zerop length)
-       (error "Kill ring is empty")
-      (setq kill-ring-yank-pointer
-           (nthcdr (% (+ arg (- length (length kill-ring-yank-pointer)))
-                      length)
-                   kill-ring)))))
-
 (defun yank-pop (arg)
   "Replace just-yanked stretch of killed-text with a different stretch.
 This command is allowed only immediately after a  yank  or a  yank-pop.
@@ -806,9 +966,8 @@ comes the newest one."
   (setq this-command 'yank)
   (let ((before (< (point) (mark))))
     (delete-region (point) (mark))
-    (rotate-yank-pointer arg)
     (set-mark (point))
-    (insert (car kill-ring-yank-pointer))
+    (insert (current-kill arg))
     (if before (exchange-point-and-mark))))
 
 (defun yank (&optional arg)
@@ -820,13 +979,20 @@ With argument n, reinsert the nth most recently killed stretch of killed
 text.
 See also the command \\[yank-pop]."
   (interactive "*P")
-  (rotate-yank-pointer (if (listp arg) 0
-                        (if (eq arg '-) -1
-                          (1- arg))))
   (push-mark (point))
-  (insert (car kill-ring-yank-pointer))
+  (insert (current-kill (cond
+                        ((listp arg) 0)
+                        ((eq arg '-) -1)
+                        (t (1- arg)))))
   (if (consp arg)
       (exchange-point-and-mark)))
+
+(defun rotate-yank-pointer (arg)
+  "Rotate the yanking point in the kill ring.
+With argument, rotate that many kills forward (or backward, if negative)."
+  (interactive "p")
+  (current-kill arg))
+
 \f
 (defun insert-buffer (buffer)
   "Insert after point the contents of BUFFER.
@@ -851,7 +1017,8 @@ It is inserted into that buffer before its point.
 When calling from a program, give three arguments:
 BUFFER (or buffer name), START and END.
 START and END specify the portion of the current buffer to be copied."
-  (interactive "BAppend to buffer: \nr")
+  (interactive
+   (list (read-buffer "Append to buffer: " (other-buffer nil t) t)))
   (let ((oldbuf (current-buffer)))
     (save-excursion
       (set-buffer (get-buffer-create buffer))
@@ -1406,11 +1573,16 @@ Setting this variable automatically makes it local to the current buffer.")
 
 (defconst comment-multi-line nil
   "*Non-nil means \\[indent-new-comment-line] should continue same comment
-on new line, with no new terminator or starter.")
+on new line, with no new terminator or starter.
+This is obsolete because you might as well use \\[newline-and-indent].")
 
 (defun indent-new-comment-line ()
   "Break line at point and indent, continuing comment if presently within one.
-The body of the continued comment is indented under the previous comment line."
+The body of the continued comment is indented under the previous comment line.
+
+This command is intended for styles where you write a comment per line,
+starting a new comment (and terminating it if necessary) on each line.
+If you want to continue one comment across several lines, use \\[newline-and-indent]."
   (interactive "*")
   (let (comcol comstart)
     (skip-chars-backward " \t")
@@ -1418,39 +1590,42 @@ The body of the continued comment is indented under the previous comment line."
                   (progn (skip-chars-forward " \t")
                          (point)))
     (insert ?\n)
-    (save-excursion
-      (if (and comment-start-skip
-              (let ((opoint (point)))
-                (forward-line -1)
-                (re-search-forward comment-start-skip opoint t)))
-         ;; The old line is a comment.
-         ;; 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)))
-           (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)))
-           ;; Indent this line like what we found.
-           (goto-char win)
-           (setq comcol (current-column))
-           (setq comstart (buffer-substring (point) (match-end 0))))))
+    (if (not comment-multi-line)
+       (save-excursion
+         (if (and comment-start-skip
+                  (let ((opoint (point)))
+                    (forward-line -1)
+                    (re-search-forward comment-start-skip opoint t)))
+             ;; The old line is a comment.
+             ;; 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)))
+               (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)))
+               ;; Indent this line like what we found.
+               (goto-char win)
+               (setq comcol (current-column))
+               (setq comstart (buffer-substring (point) (match-end 0)))))))
     (if comcol
        (let ((comment-column comcol)
              (comment-start comstart)
              (comment-end comment-end))
          (and comment-end (not (equal comment-end ""))
-              (if (not comment-multi-line)
+;             (if (not comment-multi-line)
                   (progn
                     (forward-char -1)
                     (insert comment-end)
                     (forward-char 1))
-                (setq comment-column (+ comment-column (length comment-start))
-                      comment-start "")))
+;               (setq comment-column (+ comment-column (length comment-start))
+;                     comment-start "")
+;                 )
+              )
          (if (not (eolp))
              (setq comment-end ""))
          (insert ?\n)
@@ -1498,8 +1673,14 @@ selective-display's value is separate for each buffer."
   (interactive "P")
   (if (eq selective-display t)
       (error "selective-display already in use for marked lines"))
-  (setq selective-display
-       (and arg (prefix-numeric-value arg)))
+  (let ((current-vpos
+        (save-restriction
+          (narrow-to-region (point-min) (point))
+          (goto-char (window-start))
+          (vertical-motion (window-height)))))
+    (setq selective-display
+         (and arg (prefix-numeric-value arg)))
+    (recenter current-vpos))
   (set-window-start (selected-window) (window-start (selected-window)))
   (princ "selective-display set to " t)
   (prin1 selective-display t)
@@ -1589,7 +1770,10 @@ when close-paren is inserted.")
 (defun set-variable (var val)
   "Set VARIABLE to VALUE.  VALUE is a Lisp object.
 When using this interactively, supply a Lisp expression for VALUE.
-If you want VALUE to be a string, you must surround it with doublequotes."
+If you want VALUE to be a string, you must surround it with doublequotes.
+
+If VARIABLE has a `variable-interactive' property, that is used as if
+it were the arg to `interactive' (which see) to interactively read the value."
   (interactive
    (let* ((var (read-variable "Set variable: "))
          (minibuffer-help-form
@@ -1608,87 +1792,14 @@ If you want VALUE to be a string, you must surround it with doublequotes."
                      (prin1 (symbol-value var))))
                nil)))))
      (list var
-          (eval-minibuffer (format "Set %s to value: " var)))))
+          (let ((prop (get var 'variable-interactive)))
+            (if prop
+                ;; Use VAR's `variable-interactive' property
+                ;; as an interactive spec for prompting.
+                (call-interactively (list 'lambda '(arg)
+                                          (list 'interactive prop)
+                                          'arg))
+              (eval-minibuffer (format "Set %s to value: " var)))))))
   (set var val))
-\f
-;These commands are defined in editfns.c
-;but they are not assigned to keys there.
-(put 'narrow-to-region 'disabled t)
-(define-key ctl-x-map "n" 'narrow-to-region)
-(define-key ctl-x-map "w" 'widen)
-
-(define-key global-map "\C-j" 'newline-and-indent)
-(define-key global-map "\C-m" 'newline)
-(define-key global-map "\C-o" 'open-line)
-(define-key esc-map "\C-o" 'split-line)
-(define-key global-map "\C-q" 'quoted-insert)
-(define-key esc-map "^" 'delete-indentation)
-(define-key esc-map "\\" 'delete-horizontal-space)
-(define-key esc-map "m" 'back-to-indentation)
-(define-key ctl-x-map "\C-o" 'delete-blank-lines)
-(define-key esc-map " " 'just-one-space)
-(define-key esc-map "z" 'zap-to-char)
-(define-key esc-map "=" 'count-lines-region)
-(define-key ctl-x-map "=" 'what-cursor-position)
-(define-key esc-map "\e" 'eval-expression)
-(define-key ctl-x-map "\e" 'repeat-complex-command)
-(define-key ctl-x-map "u" 'advertised-undo)
-(define-key global-map "\C-_" 'undo)
-(define-key esc-map "!" 'shell-command)
-(define-key esc-map "|" 'shell-command-on-region)
-
-(define-key global-map "\C-u" 'universal-argument)
-(let ((i ?0))
-  (while (<= i ?9)
-    (define-key esc-map (char-to-string i) 'digit-argument)
-    (setq i (1+ i))))
-(define-key esc-map "-" 'negative-argument)
-
-(define-key global-map "\C-k" 'kill-line)
-(define-key global-map "\C-w" 'kill-region)
-(define-key esc-map "w" 'kill-ring-save)
-(define-key esc-map "\C-w" 'append-next-kill)
-(define-key global-map "\C-y" 'yank)
-(define-key esc-map "y" 'yank-pop)
-
-(define-key ctl-x-map "a" 'append-to-buffer)
-
-(define-key global-map "\C-@" 'set-mark-command)
-(define-key ctl-x-map "\C-x" 'exchange-point-and-mark)
-
-(define-key global-map "\C-n" 'next-line)
-(define-key global-map "\C-p" 'previous-line)
-(define-key ctl-x-map "\C-n" 'set-goal-column)
-
-(define-key global-map [up] 'previous-line)
-(define-key global-map [down] 'next-line)
-(define-key global-map [left] 'backward-char)
-(define-key global-map [right] 'forward-char)
-
-(define-key global-map "\C-t" 'transpose-chars)
-(define-key esc-map "t" 'transpose-words)
-(define-key esc-map "\C-t" 'transpose-sexps)
-(define-key ctl-x-map "\C-t" 'transpose-lines)
-
-(define-key esc-map ";" 'indent-for-comment)
-(define-key esc-map "j" 'indent-new-comment-line)
-(define-key esc-map "\C-j" 'indent-new-comment-line)
-(define-key ctl-x-map ";" 'set-comment-column)
-(define-key ctl-x-map "f" 'set-fill-column)
-(define-key ctl-x-map "$" 'set-selective-display)
-
-(define-key esc-map "@" 'mark-word)
-(define-key esc-map "f" 'forward-word)
-(define-key esc-map "b" 'backward-word)
-(define-key esc-map "d" 'kill-word)
-(define-key esc-map "\177" 'backward-kill-word)
-
-(define-key esc-map "<" 'beginning-of-buffer)
-(define-key esc-map ">" 'end-of-buffer)
-(define-key ctl-x-map "h" 'mark-whole-buffer)
-(define-key esc-map "\\" 'delete-horizontal-space)
-
-(fset 'mode-specific-command-prefix (make-sparse-keymap))
-(defconst mode-specific-map (symbol-function 'mode-specific-command-prefix)
-  "Keymap for characters following C-c.")
-(define-key global-map "\C-c" 'mode-specific-command-prefix)
+
+;;; simple.el ends here