*** empty log message ***
[bpt/emacs.git] / lisp / simple.el
index 0d4ca3f..6c7cce5 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
@@ -99,12 +101,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 +117,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 +126,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 +146,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 +160,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 +238,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))
@@ -332,10 +352,26 @@ the minibuffer, then read and evaluate the result."
 
 ;; (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)
+(defvar minibuffer-history nil)
+(defvar minibuffer-history-sexp-flag nil)
+(setq minibuffer-history-variable 'minibuffer-history)
+(setq minibuffer-history-position nil)
+
+(define-key minibuffer-local-map "\en" 'next-history-element)
+(define-key minibuffer-local-ns-map "\en" 'next-history-element)
+(define-key minibuffer-local-ns-map "\en" 'next-history-element)
+(define-key minibuffer-local-completion-map "\en" 'next-history-element)
+(define-key minibuffer-local-completion-map "\en" 'next-history-element)
+(define-key minibuffer-local-must-match-map "\en" 'next-history-element)
+
+(define-key minibuffer-local-map "\ep" 'previous-history-element)
+(define-key minibuffer-local-ns-map "\ep" 'previous-history-element)
+(define-key minibuffer-local-ns-map "\ep" 'previous-history-element)
+(define-key minibuffer-local-completion-map "\ep" 'previous-history-element)
+(define-key minibuffer-local-completion-map "\ep" 'previous-history-element)
+(define-key minibuffer-local-must-match-map "\ep" 'previous-history-element)
+
+(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.
@@ -345,15 +381,19 @@ it is added to the front of the command history.
 Whilst editing the command, the following commands are available:
 \\{repeat-complex-command-map}"
   (interactive "p")
-  (let ((elt (nth (1- repeat-complex-command-arg) command-history))
+  (let ((elt (nth (1- arg) command-history))
+       (minibuffer-history-position arg)
+       (minibuffer-history-sexp-flag t)
        (repeat-complex-command-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))
@@ -361,27 +401,31 @@ Whilst editing the command, the following commands are available:
          (eval newcmd))
       (ding))))
 
-(defun next-complex-command (n)
-  "Inserts the next element of `command-history' into the minibuffer."
+(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)
+                  "No following item in minibuffer history"
+                "No preceding item in minibuffer history"))
       (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)))
+;;  (if repeat-complex-command-flag
+  (next-history-element (- n)))
+;;    (repeat-complex-command 1)))
 
 (defun goto-line (arg)
   "Goto line ARG, counting from line 1 at beginning of buffer."
@@ -402,7 +446,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)))
@@ -587,60 +632,73 @@ Digits or minus sign following \\[universal-argument] make up the numeric argume
 Repeating \\[universal-argument] without digits or minus sign
  multiplies the argument by 4 each time."
   (interactive nil)
-  (let ((c-u 4) (argstartchar last-command-char)
-       char)
-;   (describe-arg (list c-u) 1)
-    (setq char (read-char))
-    (while (= char argstartchar)
-      (setq c-u (* 4 c-u))
-;     (describe-arg (list c-u) 1)
-      (setq char (read-char)))
-    (prefix-arg-internal char c-u nil)))
-
-(defun prefix-arg-internal (char c-u value)
+  (let ((factor 4)
+       key)
+;;    (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 t)))
+    (prefix-arg-internal key factor nil)))
+
+(defun prefix-arg-internal (key factor value)
   (let ((sign 1))
     (if (and (numberp value) (< value 0))
        (setq sign -1 value (- value)))
     (if (eq value '-)
        (setq sign -1 value nil))
-;   (describe-arg value sign)
-    (while (= ?- char)
-      (setq sign (- sign) c-u nil)
-;     (describe-arg value sign)
-      (setq char (read-char)))
-    (while (and (>= char ?0) (<= char ?9))
-      (setq value (+ (* (if (numberp value) value 0) 10) (- char ?0)) c-u nil)
-;     (describe-arg value sign)
-      (setq char (read-char)))
-    ;; Repeating the arg-start char after digits
-    ;; terminates the argument but is ignored.
-    (if (eq (lookup-key global-map (make-string 1 char)) 'universal-argument)
-       (setq char (read-char)))
+;   (describe-arg value sign)
+    (while (equal key "-")
+      (setq sign (- sign) factor 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 t)))
     (setq prefix-arg
-         (cond (c-u (list c-u))
+         (cond (factor (list factor))
                ((numberp value) (* value sign))
                ((= sign -1) '-)))
-    (setq unread-command-char char)))
-
-;(defun describe-arg (value sign)
-; (cond ((numberp value)
-;       (message "Arg: %d" (* value sign)))
-;      ((consp value)
-;       (message "Arg: C-u factor %d" (car value)))
-;      ((< sign 0)
-;       (message "Arg: -"))))
+    ;; Calling universal-argument after digits
+    ;; terminates the argument but is ignored.
+    (if (eq (key-binding key) 'universal-argument)
+       (progn
+         (describe-arg value sign)
+         (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.
+       (setq unread-command-char (string-to-char key))
+      ;; We can't push back a longer string, so we'll emulate the
+      ;; command loop ourselves.
+      (command-execute (key-binding key)))))
+
+(defun describe-arg (value sign)
+  (cond ((numberp value)
+        (message "Arg: %d" (* value sign)))
+       ((consp value)
+        (message "Arg: [%d]" (car value)))
+       ((< sign 0)
+        (message "Arg: -"))))
 
 (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")
-  (prefix-arg-internal last-command-char nil arg))
+  (prefix-arg-internal (char-to-string (logand last-command-char ?\177))
+                      nil arg))
 
 (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")
-  (prefix-arg-internal ?- nil arg))
+  (prefix-arg-internal "-" nil arg))
 \f
 (defun forward-to-indentation (arg)
   "Move forward ARG lines and position at first nonblank character."
@@ -673,10 +731,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.")
@@ -684,11 +785,64 @@ 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))))
+;;; RMS: Turn off the interprogram paste feature 
+;;; because currently it is wedged: it is always
+;;; giving a null string.
+    (setq interprogram-paste nil)
+    (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.
@@ -704,46 +858,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 x-select-kill nil)
+    (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 (and (eq window-system 'x) x-select-kill)
-      (x-own-selection (car kill-ring) (selected-screen)))
-  (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."
@@ -754,17 +915,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.
@@ -784,9 +934,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)
@@ -798,13 +947,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.
@@ -829,7 +985,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))
@@ -1011,7 +1168,7 @@ The beginning of a blank line does not count as the end of a line.")
   "Current goal column for vertical motion.
 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."
+When the `track-eol' feature is doing its job, the value is 9999.")
 
 (defun line-move (arg)
   (if (not (or (eq last-command 'next-line)
@@ -1384,11 +1541,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")
@@ -1396,39 +1558,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)
@@ -1476,8 +1641,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)
@@ -1567,7 +1738,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
@@ -1586,82 +1760,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 "\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