* etags.el (find-tag-noselect): Doc fix.
[bpt/emacs.git] / lisp / simple.el
index 8519219..e849e63 100644 (file)
@@ -1,11 +1,12 @@
-;; Basic editing commands for Emacs
+;;; 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,
 ;; 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
-prefix, inserts the fill prefix after the newline that it inserts.
-With arg, inserts that many newlines."
+  "Insert a newline and leave point before it.
+If there is a fill prefix, insert the fill prefix on the new line
+if the line would have been empty.
+With arg N, insert N newlines."
   (interactive "*p")
-  (let ((flag (and (bolp) (not (bobp)))))
-    (if flag (forward-char -1))
+  (let* ((do-fill-prefix (and fill-prefix (bolp)))
+        (flag (and (null do-fill-prefix) (bolp) (not (bobp)))))
+    ;; If this is a simple case, and we are at the beginning of a line,
+    ;; actually insert the newline *before* the preceding newline
+    ;; instead of after.  That makes better display behavior.
+    (if flag
+       (progn
+         ;; If undo is enabled, don't let this hack be visible:
+         ;; record the real value of point as the place to move back to
+         ;; if we undo this insert.
+         (if (and buffer-undo-list (not (eq buffer-undo-list t)))
+             (setq buffer-undo-list (cons (point) buffer-undo-list)))
+         (forward-char -1)))
     (while (> arg 0)
       (save-excursion
-        (insert ?\n)
-       (if fill-prefix (insert fill-prefix)))
+        (insert ?\n))
+      (if do-fill-prefix (insert fill-prefix))
       (setq arg (1- arg)))
     (if flag (forward-char 1))))
 
@@ -44,7 +58,7 @@ With arg, inserts that many newlines."
 
 (defun quoted-insert (arg)
   "Read next input character and insert it.
-Useful for inserting control characters.
+This is useful for inserting control characters.
 You may also type up to 3 octal digits, to insert a character with that code"
   (interactive "*p")
   (let ((char (read-quoted-char)))
@@ -54,6 +68,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 +76,14 @@ 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
+                (<= (+ (point) (length fill-prefix)) (point-max))
+                (string= fill-prefix
+                         (buffer-substring (point)
+                                           (+ (point) (length fill-prefix)))))
+           (delete-region (point) (+ (point) (length fill-prefix))))
        (fixup-whitespace))))
 
 (defun fixup-whitespace ()
@@ -99,12 +122,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 +138,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 +147,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."
@@ -130,27 +161,27 @@ On nonblank line, delete all blank lines that follow it."
 
 (defun newline-and-indent ()
   "Insert a newline, then indent according to major mode.
-Indentation is done using the current indent-line-function.
+Indentation is done using the value of `indent-line-function'.
 In programming language modes, this is the same as TAB.
-In some text modes, where TAB inserts a tab, this indents to the
-specified left-margin column."
+In some text modes, where TAB inserts a tab, this command indents to the
+column specified by the variable `left-margin'."
   (interactive "*")
   (delete-region (point) (progn (skip-chars-backward " \t") (point)))
-  (insert ?\n)
+  (newline)
   (indent-according-to-mode))
 
 (defun reindent-then-newline-and-indent ()
   "Reindent current line, insert newline, then indent the new line.
 Indentation of both lines is done according to the current major mode,
-which means that the current value of indent-line-function is called.
+which means calling the current value of `indent-line-function'.
 In programming language modes, this is the same as TAB.
 In some text modes, where TAB inserts a tab, this indents to the
-specified left-margin column."
+column specified by the variable `left-margin'."
   (interactive "*")
   (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
@@ -200,7 +231,8 @@ Goes backward if ARG is negative; error if CHAR not found."
 (defun beginning-of-buffer (&optional arg)
   "Move point to the beginning of the buffer; leave mark at previous position.
 With arg N, put point N/10 of the way from the true beginning.
-Don't use this in Lisp programs!
+
+Don't use this command in Lisp programs!
 \(goto-char (point-min)) is faster and avoids clobbering the mark."
   (interactive "P")
   (push-mark)
@@ -216,7 +248,8 @@ Don't use this in Lisp programs!
 (defun end-of-buffer (&optional arg)
   "Move point to the end of the buffer; leave mark at previous position.
 With arg N, put point N/10 of the way from the true end.
-Don't use this in Lisp programs!
+
+Don't use this command in Lisp programs!
 \(goto-char (point-max)) is faster and avoids clobbering the mark."
   (interactive "P")
   (push-mark)
@@ -228,13 +261,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))
@@ -259,7 +302,7 @@ Don't use this in Lisp programs!
 (defun count-lines (start end)
   "Return number of lines between START and END.
 This is usually the number of newlines between them,
-but will be one more if START is not equal to END
+but can be one more if START is not equal to END
 and the greater of them is not at the start of a line."
   (save-excursion
     (save-restriction
@@ -308,14 +351,19 @@ Other major modes are defined by comparison with this one."
   (interactive)
   (kill-all-local-variables))
 
+(defvar read-expression-map (copy-keymap minibuffer-local-map)
+  "Minibuffer keymap used for reading Lisp expressions.")
+(define-key read-expression-map "\M-\t" 'lisp-complete-symbol)
+
 (put 'eval-expression 'disabled t)
 
 ;; We define this, rather than making  eval  interactive,
 ;; 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."
-  (interactive "xEval: ")
+Value is also consed on to front of the variable `values'."
+  (interactive (list (read-from-minibuffer "Eval: "
+                                          nil read-expression-map t)))
   (setq values (cons (eval expression) values))
   (prin1 (car values) t))
 
@@ -323,66 +371,156 @@ Value is also consed on to front of variable  values  's value."
   "Prompting with PROMPT, let user edit COMMAND and eval result.
 COMMAND is a Lisp expression.  Let user edit that expression in
 the minibuffer, then read and evaluate the result."
-  (let ((command (read-minibuffer prompt
-                                 (prin1-to-string command))))
+  (let ((command (read-from-minibuffer prompt
+                                      (prin1-to-string command)
+                                      read-expression-map t)))
     ;; Add edited command to command history, unless redundant.
     (or (equal command (car command-history))
        (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
          (setq newcmd (read-from-minibuffer "Redo: "
                                             (prin1-to-string elt)
-                                            repeat-complex-command-map
-                                            t))
+                                            read-expression-map
+                                            t
+                                            (cons 'command-history
+                                                  arg)))
+         ;; If command was added to command-history as a string,
+         ;; get rid of that.  We want only evallable expressions there.
+         (if (stringp (car command-history))
+             (setq command-history (cdr command-history)))
          ;; 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
+  "Default minibuffer history list.
+This is used for all minibuffer input
+except when an alternate history list is specified.")
+(defvar minibuffer-history-sexp-flag nil
+  "Nonzero when doing history operations on `command-history'.
+More generally, indicates that the history list being acted on
+contains expressions rather than strings.")
+(setq minibuffer-history-variable 'minibuffer-history)
+(setq minibuffer-history-position nil)
+(defvar minibuffer-history-search-history 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
+               read-expression-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)))
+
+(defun previous-matching-history-element (regexp n)
+  "Find the previous history element that matches REGEXP.
+\(Previous history elements refer to earlier actions.)
+With prefix argument N, search for Nth previous match.
+If N is negative, find the next or Nth next match."
+  (interactive
+   (let ((enable-recursive-minibuffers t)
+        (minibuffer-history-sexp-flag nil))
+     (list (read-from-minibuffer "Previous element matching (regexp): "
+                                nil
+                                minibuffer-local-map
+                                nil
+                                'minibuffer-history-search-history)
+          (prefix-numeric-value current-prefix-arg))))
+  (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)))
+  (if (or (eq (car (car command-history)) 'previous-matching-history-element)
+         (eq (car (car command-history)) 'next-matching-history-element))
+      (setq command-history (cdr command-history))))
+
+(defun next-matching-history-element (regexp n)
+  "Find the next history element that matches REGEXP.
+\(The next history element refers to a more recent action.)
+With prefix argument N, search for Nth next match.
+If N is negative, find the previous or Nth previous match."
+  (interactive
+   (let ((enable-recursive-minibuffers t)
+        (minibuffer-history-sexp-flag nil))
+     (list (read-from-minibuffer "Next element matching (regexp): "
+                                nil
+                                minibuffer-local-map
+                                nil
+                                'minibuffer-history-search-history)
+          (prefix-numeric-value current-prefix-arg))))
+  (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)
-  "Inserts the previous element of `command-history' into the minibuffer."
+(defun previous-history-element (n)
+  "Inserts the previous element of the minibuffer 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: ")
@@ -413,16 +551,16 @@ A numeric argument serves as a repeat count."
         (delete-auto-save-file-if-necessary))))
 
 (defun undo-start ()
-  "Move pending-undo-list to front of undo records.
-The next call to undo-more will undo the most recently made change."
+  "Set `pending-undo-list' to the front of the undo list.
+The next call to `undo-more' will undo the most recently made change."
   (if (eq buffer-undo-list t)
       (error "No undo information in this buffer"))
   (setq pending-undo-list buffer-undo-list))
 
 (defun undo-more (count)
   "Undo back N undo-boundaries beyond what was already undone recently.
-Call undo-start to get ready to undo recent changes,
-then call undo-more one or more times to undo them."
+Call `undo-start' to get ready to undo recent changes,
+then call `undo-more' one or more times to undo them."
   (or pending-undo-list
       (error "No further undo information"))
   (setq pending-undo-list (primitive-undo count pending-undo-list)))
@@ -526,7 +664,7 @@ but it is nonetheless available in buffer `*Shell Command Output*'
 even though that buffer is not automatically displayed.  If there is no output
 or output is inserted in the current buffer then `*Shell Command Output*' is
 deleted." 
-  (interactive (list (min (point) (mark)) (max (point) (mark))
+  (interactive (list (region-beginning) (region-end)
                     (read-string "Shell command on region: "
                                  last-shell-command-on-region)
                     current-prefix-arg
@@ -590,12 +728,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)
@@ -604,19 +742,20 @@ 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)))
-    (while (and (= (length key) 1)
+;;      (describe-arg value sign)
+      (setq key (read-key-sequence nil t)))
+    (while (and (stringp key)
+               (= (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))
@@ -626,7 +765,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.
@@ -687,10 +826,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.")
@@ -698,11 +880,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.
@@ -718,58 +949,56 @@ 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."
+  "Cause following command, if it kills, to append to previous kill."
   (interactive)
   (if (interactive-p)
       (progn
@@ -777,27 +1006,16 @@ 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.
+  "Replace just-yanked stretch of killed text with a different stretch.
+This command is allowed only immediately after a `yank' or a `yank-pop'.
 At such a time, the region contains a stretch of reinserted
-previously-killed text.  yank-pop  deletes that text and inserts in its
+previously-killed text.  `yank-pop' deletes that text and inserts in its
 place a different stretch of killed text.
 
 With no argument, the previous kill is inserted.
-With argument n, the n'th previous kill is inserted.
-If n is negative, this is a more recent kill.
+With argument N, insert the Nth previous kill.
+If N is negative, this is a more recent kill.
 
 The sequence of kills wraps around, so that after the oldest one
 comes the newest one."
@@ -807,33 +1025,40 @@ 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)
   "Reinsert the last stretch of killed text.
 More precisely, reinsert the stretch of killed text most recently
-killed OR yanked.
-With just C-U as argument, same but put point in front (and mark at end).
-With argument n, reinsert the nth most recently killed stretch of killed
+killed OR yanked.  Put point at end, and set mark at beginning.
+With just C-u as argument, same but put point at beginning (and mark at end).
+With argument N, reinsert the Nth most recently killed stretch of killed
 text.
 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.
 Puts mark after the inserted text.
 BUFFER may be a buffer or a buffer name."
-  (interactive (list (read-buffer "Insert buffer: " (other-buffer) t)))
+  (interactive (list (progn (barf-if-buffer-read-only)
+                           (read-buffer "Insert buffer: " (other-buffer) t))))
   (or (bufferp buffer)
       (setq buffer (get-buffer buffer)))
   (let (start end newmark)
@@ -852,7 +1077,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))
@@ -902,7 +1128,7 @@ mark position to be lost.
 Normally, when a new mark is set, the old one should go on the stack.
 This is why most applications should use push-mark, not set-mark.
 
-Novice emacs-lisp programmers often try to use the mark for the wrong
+Novice Emacs Lisp programmers often try to use the mark for the wrong
 purposes.  The mark saves a location for the user's convenience.
 Most editing commands should not alter the mark.
 To remember a location for internal use in the Lisp program,
@@ -925,7 +1151,7 @@ most recent first.")
 With no prefix argument, set mark, and push previous mark on mark ring.
 With argument, jump to mark, and pop into mark off the mark ring.
 
-Novice emacs-lisp programmers often try to use the mark for the wrong
+Novice Emacs Lisp programmers often try to use the mark for the wrong
 purposes.  See the documentation of `set-mark' for more information."
   (interactive "P")
   (if (null arg)
@@ -939,7 +1165,7 @@ purposes.  See the documentation of `set-mark' for more information."
   "Set mark at LOCATION (point, by default) and push old mark on mark ring.
 Displays \"Mark set\" unless the optional second arg NOMSG is non-nil.
 
-Novice emacs-lisp programmers often try to use the mark for the wrong
+Novice Emacs Lisp programmers often try to use the mark for the wrong
 purposes.  See the documentation of `set-mark' for more information."
   (if (null (mark))
       nil
@@ -1026,9 +1252,9 @@ to use and more reliable (no dependence on goal column, etc.)."
 This means moving to the end of each line moved onto.
 The beginning of a blank line does not count as the end of a line.")
 
-(make-variable-buffer-local
- (defvar goal-column nil
-   "*Semipermanent goal column for vertical motion, as set by \\[set-goal-column], or nil."))
+(defvar goal-column nil
+  "*Semipermanent goal column for vertical motion, as set by \\[set-goal-column], or nil.")
+(make-variable-buffer-local 'goal-column)
 
 (defvar temporary-goal-column 0
   "Current goal column for vertical motion.
@@ -1067,7 +1293,8 @@ When the `track-eol' feature is doing its job, the value is 9999.")
 Those commands will move to this position in the line moved to
 rather than trying to keep the same horizontal position.
 With a non-nil argument, clears out the goal column
-so that \\[next-line] and \\[previous-line] resume vertical motion."
+so that \\[next-line] and \\[previous-line] resume vertical motion.
+The goal column is stored in the variable `goal-column'."
   (interactive "P")
   (if arg
       (progn
@@ -1329,7 +1556,8 @@ not end the comment.  Blank lines do not get comments."
                     (skip-chars-backward " \t")
                     (backward-char (length ce))
                     (if (looking-at (regexp-quote ce))
-                        (delete-char (length ce))))))
+                        (delete-char (length ce)))))
+               (forward-line 1))
             (if (looking-at "[ \t]*$") ()
               (insert cs)
               (if (string= "" ce) ()
@@ -1340,7 +1568,7 @@ not end the comment.  Blank lines do not get comments."
 (defun backward-word (arg)
   "Move backward until encountering the end of a word.
 With argument, do this that many times.
-In programs, it is faster to call forward-word with negative arg."
+In programs, it is faster to call `forward-word' with negative arg."
   (interactive "p")
   (forward-word (- arg)))
 
@@ -1356,7 +1584,7 @@ In programs, it is faster to call forward-word with negative arg."
   "Kill characters forward until encountering the end of a word.
 With argument, do this that many times."
   (interactive "p")
-  (kill-region (point) (progn (forward-word arg) (point))))
+  (kill-region (point) (save-excursion (forward-word arg) (point))))
 
 (defun backward-kill-word (arg)
   "Kill characters backward until encountering the end of a word.
@@ -1407,11 +1635,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")
@@ -1419,39 +1652,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)
@@ -1485,22 +1721,28 @@ automatically breaks the line at a previous space."
   (auto-fill-mode 1))
 
 (defun set-fill-column (arg)
-  "Set fill-column to current column, or to argument if given.
-fill-column's value is separate for each buffer."
+  "Set `fill-column' to current column, or to argument if given.
+The variable `fill-column' has a separate value for each buffer."
   (interactive "P")
   (setq fill-column (if (integerp arg) arg (current-column)))
   (message "fill-column set to %d" fill-column))
 \f
 (defun set-selective-display (arg)
-  "Set selective-display to ARG; clear it if no arg.
-When selective-display is a number > 0,
-lines whose indentation is >= selective-display are not displayed.
-selective-display's value is separate for each buffer."
+  "Set `selective-display' to ARG; clear it if no arg.
+When the value of `selective-display' is a number > 0,
+lines whose indentation is >= that value are not displayed.
+The variable `selective-display' has a separate value 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)
@@ -1590,7 +1832,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
@@ -1609,87 +1854,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