[comp.emacs] Emacs documentation gouger

rbj@ICST-CMR.ARPA (Root Boy Jim) (06/03/88)

I have about six of these things. Why doesn't a Gnuru (my thought immediately
run to Dan La Liberte or /jr) add this to the lisp directory. While you're
at it, please add filename completion to the shell as well. In fact,
what would really be nice is to add C-c C-[pn] to do up/down history
as well. I would do it, but I'm lazy, and others know better than I do.
To jkh@violet, I will mail you my rmail file with all the versions.

wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (06/04/88)

In article <8806031450.AA08287@icst-cmr.arpa> rbj@ICST-CMR.ARPA (Root Boy Jim) writes:
>While you're at it, please add filename completion to the shell as
>well. In fact, what would really be nice is to add C-c C-[pn] to do
>up/down history as well. I would do it, but I'm lazy, and others know
>better than I do.

This is a ksh-like extention to shell.el.  These extentiions implement
command history (backwards, forwards, back-search, forward-srearch),
filename completion, .history file read-in and history printout for an
emacs shell window.

The one glaring difference between this and ksh, is that all of the
shell-mode commands are bound to the Control-C prefix map. (Eg.
previous command is C-c C-p).

There are also some extensions to the normal inferior lisp stuff.

The full list of shell commands is:

	RET             shell-send-input
	C-c             Prefix Command

	C-c C-a         shell-beginning-of-line
	C-c C-c         interrupt-shell-subjob
	C-c C-d         shell-send-eof
	C-c C-h         Prefix Command
	C-c TAB         shell-filename-expand
	C-c RET         shell-push-input
	C-c C-n         shell-next-command
	C-c C-o         kill-output-from-shell
	C-c C-p         shell-previous-command
	C-c C-r         shell-history-search-backward
	C-c C-s         shell-history-search-forward
	C-c C-u         kill-shell-input
	C-c C-w         backward-kill-word
	C-c C-x         Prefix Command
	C-c C-y         copy-last-shell-input
	C-c C-z         stop-shell-subjob
	C-c ESC         Prefix Command
	C-c C-\         quit-shell-subjob
	C-c [           show-output-from-shell
	C-c b           shell-save-output
	C-c h           shell-list-history

	C-c C-h v       inferior-lisp-help
	C-c C-h C-h     inferior-lisp-help-help
	C-c C-h f       inferior-lisp-help
	C-c C-h a       inferior-lisp-apropos
	C-c C-x C-e     inferior-eval-last-sexp
	C-c ESC C-x     inferior-eval-defun

This is a diff for shell.el(18.51) (to add a few hooks, and some
personal bug-fixes/hacks) and a file shellext.el, which does the real
work.

This basic code has been running on 18.26 as well as 18.49 and 18.51,
so you shouldn't have much trouble, even on older emacses.

			-enjoy
			wolfgang

----cut here---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;									     ;;
;;	File:     shellext.el						     ;;
;;	Author:   Wolfgang Rupprecht					     ;;
;;      Address:  wolfgang@mgm.mit.edu (IP addr 18.82.0.114)                 ;;
;;	Created:  Mon Oct 12 18:52:34 EDT 1987				     ;;
;;	Contents: ksh-like extensions to shell.el		             ;;
;;									     ;;
;;	Copyright (c) 1987 Wolfgang Rupprecht.				     ;;
;;									     ;;
;;	$Log$								     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; GNU Emacs and this file "shellext.el", is distributed in the hope
;; that it will be useful, but WITHOUT ANY WARRANTY.  No author or
;; distributor accepts responsibility to anyone for the consequences
;; of using it or for whether it serves any particular purpose or
;; works at all, unless he says so in writing.  Refer to the GNU Emacs
;; General Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute GNU
;; Emacs and shellext.el, but only under the conditions described in
;; the GNU Emacs General Public License.  A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you can
;; know your rights and responsibilities.  It should be in a file
;; named COPYING.  Among other things, the copyright notice and this
;; notice must be preserved on all copies.

;; If you like this shell hack, and would like other custom
;; non-proprietary GnuEmacs extensions, let me know. I may be
;; interested in doing it for you on a contract basis. -wsr

(provide 'shellext)			; for require 'shellext in 
					; patched shell.el

(defvar shell-last-search "" "Last shell search string.")
(defvar shell-max-history 60
  "*Max shell history retained")
(defvar shell-history-list nil
  "History list of past shell commands.")
(defvar shell-history-index -1
  "Where we are on the history list. It is -1 unless currently
walking up/down the list")
(defvar shell-history-list-order nil
  "*If t, list shell history with most recent command last." nil)
(defvar shell-read-history t
  "*If t, the emacs shell will read in the user's ~/.history file.
This somewhat slows down shell startup.")
; TODO: add ~ expansion
; (defvar shell-expand-twiddle t
;  "*If non-Nil then shell-filename-expand will expand ~ to the pathname
; of your home directory. If nil, then ~ is left unexpanded.")

(define-key shell-mode-map "\C-c\t" 'shell-filename-expand)
(define-key shell-mode-map "\C-c\C-p" 'shell-previous-command)
(define-key shell-mode-map "\C-c\C-n" 'shell-next-command)
(define-key shell-mode-map "\C-c\C-r" 'shell-history-search-backward)
(define-key shell-mode-map "\C-c\C-s" 'shell-history-search-forward)
(define-key shell-mode-map "\C-ch" 'shell-list-history)
(define-key shell-mode-map "\C-c\C-a" 'shell-beginning-of-line)
(define-key shell-mode-map "\C-c\r" 'shell-push-input)
(define-key shell-mode-map "\C-cb" 'shell-save-output)
; and now rebind 'show-output-from shell (which was on C-cC-r)
(define-key shell-mode-map "\C-c[" 'show-output-from-shell)

(defun shell-filename-expand ()
  "Complete the filename before (point) as far as possible."
	(interactive)	       
	  (let* ((end (point))
		 (beg (progn
			(re-search-backward "[ \t\n;]")
			(forward-char 1)
			(point)))
		 (new (path-name-completion (buffer-substring beg end))))
	    (cond ((eq new t)
		   (progn
		     (goto-char end)
		     (message "File name is already complete")))
		  ((null new)
		   (progn
		     (goto-char end)
		     (error "No completion possible")))
		   (t
		    (progn
		      (delete-region beg end)
		      (insert new))))))

(defun path-name-completion (path-name)
  "Complete PATHNAME as far as possible, return this string."
  (let* ((dir (file-name-directory path-name))
	 (file (file-name-nondirectory path-name))
	 (completion
	   (file-name-completion file (or dir ""))))
    (if (string-equal file completion)	; we are at a branch point
	(let ((list (sort (file-name-all-completions (or file "") (or dir ""))
			  'string-lessp)))
	  (with-output-to-temp-buffer " *Completions*"
		    (princ "Possible completions are:\n")
		    (while list
		      ;; -40 padding spec doesn't work !!!
		      ;; (princ (format "%-40s %s" (car list)
		      ;;                (or (car (cdr list)) "")))
		      (princ (car list))
		      (if (cdr list)
			  (progn
			    (princ
			      (make-string
				(- 35 (length (car list)))
				?\ ))
			    (princ (car (cdr list)))))
		      (terpri)
		      (setq list (cdr (cdr list)))))
		  path-name)		; give 'em back their input
      ;; BUG?: emacs outputs to wrong-buffer (inserted text destined for
      ;; the *shell* buffer goes to next buffer on buffer list.)
      ;; Seemingly unneeded save-excursion around kill-buffer solves
      ;; this problem. -wsr
      (save-excursion
	(let ((buffer (get-buffer " *Completions*")))
	  (if buffer (kill-buffer buffer))))
      (if dir
	  (and completion (or (eq completion t)	; leave t or nil alone
			      (concat dir completion)))
	completion))))

(defun shell-previous-command ()
  "Insert the previous command into the shell buffer."
  (interactive)
  (let ((history (nthcdr (1+ shell-history-index) shell-history-list)))
    (if history
	(progn
	  (delete-region (process-mark (get-buffer-process (current-buffer)))
			 (point-max))
	  (goto-char (point-max))
	  (insert (car history))
	  (setq shell-history-index (1+ shell-history-index)))
;	  (message "history %d" shell-history-index)
      (error "End of history list, (history %d)" shell-history-index))))

(defun shell-next-command ()
  "Insert the next command into the shell buffer."
  (interactive)
  (delete-region (process-mark (get-buffer-process (current-buffer)))
	       (point-max))
  (goto-char (point-max))
  (if (<= 0 shell-history-index)  
      (setq shell-history-index (1- shell-history-index))
    (error "Top of history list (history %d)" shell-history-index))
  (if (<= 0 shell-history-index)
      (progn 
;	(message "history %d" shell-history-index)
	(insert (nth shell-history-index shell-history-list)))))

(defun shell-history-search-backward (string)
  "Search the history list for an occurance of STRING."
  (interactive (list (setq shell-last-search
			   (read-string
			    "History search for: " shell-last-search))))
  (let* ((index (1+ shell-history-index)) ; start at next command
	 (history (nthcdr index shell-history-list)))
    (while (and history
		(null (string-match string (car history))))
      (setq index (1+ index)
	    history (cdr history)))
    (if history
	(progn
	  (setq shell-history-index index)
	  (delete-region (process-mark (get-buffer-process (current-buffer)))
			 (point-max))
	  (goto-char (point-max))
	  (insert (car history))
;	  (message "history %d" shell-history-index)
	  )
      (error "No match found, history %d" shell-history-index))))


(defun shell-history-search-forward (string)
  "Search the history list for an occurance of STRING."
  (interactive (list (setq shell-last-search
			   (read-string
			    "History search for: " shell-last-search))))
  (let ((index shell-history-index))
    (while (and (<= 0 index)		; not as effecient as backwards hum...
		(null (string-match
		       string (nth (setq index (1- index))
				   shell-history-list)))))
    ;; index is bounded by: (-1 <= index <= shell-history-index) 
    (if (<= 0 index)
	(progn
	  (setq shell-history-index index)
	  (delete-region (process-mark (get-buffer-process (current-buffer)))
			 (point-max))
	  (goto-char (point-max))
	  (insert (or (nth index shell-history-list) ""))
;	  (message "history %d" shell-history-index)
	  )
      (error "No match found, history %d" shell-history-index))))

(defun shell-list-history ()
  "List the history in the *History* buffer. A '*' indicates current
position on the history list."
  (interactive)
  (with-output-to-temp-buffer "*History*"
    (if shell-history-list-order
	(let ((history (reverse (cons "<none>" shell-history-list)))
	      (index (1- (length shell-history-list))))
	  (while history
	    (princ (format "%c [%d] %s\n" 
			   (if (= index shell-history-index)
			       ?* ?\ )
			   index (car history)))
	    (setq history (cdr history)
		  index (1- index))))
      (let ((history (cons "<none>" shell-history-list))
	    (index -1))
	(while history
	  (princ (format "%c [%d] %s\n" 
			 (if (= index shell-history-index)
			     ?* ?\ )
			 index (car history)))
	  (setq history (cdr history)
		index (1+ index)))))))

(defun shell-beginning-of-line ()
  "Goto the beggining of the commad line. (ie. just after the prompt)"
  (interactive)
  (goto-char (process-mark (get-buffer-process (current-buffer)))))

(defun shell-input-history-file ()
  "Read in the user's ~/.history file."
  (if shell-history-list		; if non-nil, it's only a shell 
      nil				; restart, so don't trash existing
					; history list.
    (let ((list nil)
	  (history-file (expand-file-name "~/.history")))
      (if (file-exists-p history-file)
	  (save-excursion
	    (set-buffer (get-buffer-create "*history-temp*"))
	    (erase-buffer)
	    (insert-file history-file)
	    (goto-char (point-min))
	    (while (re-search-forward "[^\^@\n]+$" nil t)
	      (setq list
		    (cons (buffer-substring (match-beginning 0)
					    (match-end 0))
			  list)))
	    (kill-buffer (current-buffer))
	    (let ((prune-pt (nthcdr shell-max-history list)))
	      (and prune-pt (rplacd prune-pt nil)))
	    (setq list (cons "*shell-history-list-marker*" list))))
      (make-local-variable 'shell-history-index)
      (make-local-variable 'shell-history-list)
      (setq shell-history-list list)
      (setq shell-history-index -1))))

(defun shell-output-history-file ()
  "Write out the user's ~/.history file from the internal history list.
Some shells *really* hate it when a shell-child shortens the history file.
For this reason we will only append to the history file."
  (interactive)				; hmm, where should I call this from?
  (let ((history-file (expand-file-name "~/.history")))
    (if (file-exists-p history-file)
	(save-excursion
	  (let ((list (reverse shell-history-list)))
	    ; Hold onto that slippery local variable. Shell-history-list
	    ; will disapear once we switch buffers.
	    ;
	    ; It's best not to do an nreverse here, since we might still
	    ; want to use the original list.
	    (set-buffer (get-buffer-create "*history-temp*"))
	    (erase-buffer)
	    (let ((new-list (member "*shell-history-list-marker*" list)))
	      (if new-list
		  (setq list (cdr new-list))))
	    (while list
	      (insert (car list) "\n\C-@")
	      (setq list (cdr list))))
	  (write-region (point-min) (point-max)
			history-file 'append 'nomsg)
	  (setq shell-history-list
		(cons "*shell-history-list-marker*"
		      ;;; \(delete "*shell-history-list-marker*"
		      shell-history-list)
		      ;;; \) 
		)))))


(if (fboundp 'member)			; supply member if it's missing.
    nil
  (defun member (elt list)		; should really be in fns.c (in C)
    "Returns non-nil if ELT is an element of LIST.  Comparison done with EQUAL.
The value is actually the tail of LIST whose car is ELT."
    (while (and list
		(not (equal elt (car list))))
      (setq list (cdr list)))
    list))
	
(defun shell-save-history ()
  "Save this command on the shell-history-list."
  (let ((command (buffer-substring last-input-start (1- last-input-end))))
    (if (or (string-match "^[ \t]*$" command)
	    (string-equal command (car shell-history-list)))
	nil				; don't hang dups on list
      (setq shell-history-list (cons command shell-history-list))
      (let ((prune-pt (nthcdr shell-max-history shell-history-list)))
	(and prune-pt (rplacd prune-pt nil)))))
  (setq shell-history-index -1))

(defun shell-push-input ()
  "Pushes all pending shell input to shell. Like \\[shell-send-input], only
it doesn't append a newline. Useful for programs that expect to talk 
to a tty in raw mode (eg. tip(1)). The pushed input doesn't get recorded
on the shell's history list."
  (interactive)
  (goto-char (point-max))
  (move-marker last-input-start
	       (process-mark (get-buffer-process (current-buffer))))
  (move-marker last-input-end (point))
  (let ((process (get-buffer-process (current-buffer))))
    (process-send-region process last-input-start last-input-end)
    (set-marker (process-mark process) (point))))

(defun shell-save-output ()
  "Save all output from shell since last input in buffer '*Shell Save
Output*'."
  (interactive)
  (goto-char (point-max))
  (beginning-of-line)
  (with-output-to-temp-buffer "*Shell Save Output*"
    (princ (buffer-substring last-input-end (point))))
  (kill-region last-input-end (point))
  (goto-char (point-max)))

;;; inferior lisp extensions

(defun inferior-lisp-bindings (keymap)
  "Setup KEYMAP to have inferior-lisp bindings."
  (define-key keymap "\C-c\C-ha" 'inferior-lisp-apropos)
  (define-key keymap "\C-c\C-hf" 'inferior-lisp-help)
  (define-key keymap "\C-c\C-h\C-h" 'inferior-lisp-help-help)
  (define-key keymap "\C-c\C-hv" 'inferior-lisp-help)
  (define-key keymap "\C-c\C-x\C-e" 'inferior-eval-last-sexp)
  (define-key keymap "\C-c\M-\C-x" 'inferior-eval-defun)
  ;; (define-key keymap "\C-c" 'inferior-)
  )

(inferior-lisp-bindings inferior-lisp-mode-map)
; (inferior-lisp-bindings lisp-mode-map)

(defun int-helper (string)
  "Query the user for a string using STRING as prompt.
Provide symbol around current buffer's point as default response."
  (list
    (read-string string
	  (save-excursion
	    (if (not (looking-at "\\s_\\|\\sw")) ; if not in a symbol
		(re-search-backward "\\s_\\|\\sw" nil t)) ; go into prev. one
	    (buffer-substring
	      (progn (forward-sexp 1) (point))
	      (progn (backward-sexp 1) (point)))))))

(defun inferior-lisp-help (string)
  "Run help on VARIABLE_OR_FUNCTION in the inferior lisp."
  (interactive (int-helper "Inferior help variable_or_function: "))
  (inferior-help (concat "(help '" string ")")))

(defun inferior-lisp-help-help ()
  "Run help help in the inferior lisp."
  (interactive)
  (inferior-help "(help)"))

(defun inferior-lisp-apropos (string)
  "Run apropos of SUBSTRING in the inferior lisp."
  (interactive "sInferior apropos substring: ")
  (if (or (null string)
	  (string-equal string ""))
      (error "You must specify a string.")
    (inferior-help (concat "(help* '" string ")"))))

(defun inferior-help (string)
  "Run STRING as an command in the inferior lisp. Displays the output
in the *Help* buffer."
  (with-output-to-temp-buffer "*Help*"
    (princ (inferior-exec-string string)))
;; code around string-match difficulties
  (set-buffer "*Help*")
  (goto-char (point-min))
  (delete-matching-lines "^-*$"))	; delete --- or blank lines

;; Doesn't work ... complains that \\( register 2 \\) is nil. Hmm.
;; a string-match bug?
;; It looks like a terminating "$" does nothing in a string-match.

;;  (let* ((pstring (inferior-exec-string string)))
;;    (string-match "^\\(---*\\s-*\n\\)+\\(.+\\)\\(\n---*\\s-*\\)+$"
;;		  pstring)
;;    (let ((sstring (substring pstring (match-beginning 2) (match-end 2))))
;;      (with-output-to-temp-buffer "*Help*"
;;	(princ sstring)
;;	))))

(defun inferior-eval-last-sexp (arg)
  "Evaluate sexp before point; print value in minibuffer.
With argument, print output into current buffer."
  (interactive "P")
  (inferior-eval-region
    (let ((stab (syntax-table)))
      (unwind-protect
	  (save-excursion
	    (set-syntax-table lisp-mode-syntax-table)
	    (forward-sexp -1)
	    (point))
	(set-syntax-table stab)))
    (point)
    (if arg (current-buffer) t)))

(defun inferior-eval-defun (arg)
  "Evaluate in the inferior lisp the defun that point is in or before.
Print value in minibuffer.
With argument, insert value in current buffer after the defun."
  (interactive "P")
  (save-excursion
    (end-of-defun)
    (let ((end (point)))
      (beginning-of-defun)
      (inferior-eval-region (point) end
			    (if arg (current-buffer) t)))))


(defun inferior-eval-region (point mark &optional buffer)
  "Execute the region as Lisp code in the inferior lisp.
When called from programs, expects two arguments,
giving starting and ending indices in the current buffer
of the text to be executed.
Programs can pass third argument PRINTFLAG which controls printing of output:
nil means discard it; anything else is stream for print."
  (interactive "r")
  (let ((string (inferior-exec-string (buffer-substring point mark))))
    (if buffer				; buffer or t for minibuffer{_
	(princ string buffer))))
 
;; most of the complications in inferior-exec-string are do to our
;; attempting to use the same lisp process for help that the user is
;; using for his own end. This forces us to muck with point and the
;; process's output marker

(defun inferior-exec-string (string)
  "Run STRING as an command in the inferior lisp. Returns result as string."
  (save-excursion
    (let* ((buffer (get-buffer "*lisp*"))
	   (process (and buffer (get-buffer-process buffer)))
	   return-string)
      (if (and buffer process
	       (eq 'run (process-status process)))
	  (set-buffer buffer)
	(message "Starting lisp process...")
	(sit-for 0)
	(run-lisp)
	(setq buffer (get-buffer "*lisp*"))
	(setq process (get-buffer-process buffer))
	(while (not (looking-at-backward inferior-lisp-prompt))
	  (accept-process-output process)
;	  (sleep-for 1)			; pack output a bit more.
	  )
	;; don't bother with a (sit-for 0)
	;; let'em they'll just think lisp is slow to start ...
	(message "Starting lisp process...done"))
      (let* ((old-end (point-max))
	     (process-marker (process-mark process))
	     (op-mark-pos (marker-position process-marker)))
	(goto-char old-end)
	(unwind-protect
	    (progn 
	      (set-marker process-marker old-end)
	      (process-send-string
		process (concat "(let ((*break-enable* nil)) " string ")\n"))
	      (condition-case error-list
		  (while (or (not (looking-at-backward inferior-lisp-prompt))
			     (= old-end (point-max)))
		    (accept-process-output process) ; non-trival bug ??
		    ;; (sleep-for 1)		; lower cpu loading
		    (goto-char (point-max)))
		(error (progn (message "Ignoring %s" error-list)
			      (sit-for 0)(ding))))
	      (goto-char (point-max))
	      (end-of-line -1)
	      (setq return-string (buffer-substring old-end (point))))
	  ;; protected forms, fix up our mucking
	  (set-marker process-marker op-mark-pos)
	  ;; (delete-region old-end (point-max)) ; also moves us to old-end
	  ))
      return-string)))

(defun looking-at-backward (regexp)
  (let* ((begin (point))
	 (found (re-search-backward regexp nil t)))
    (goto-char begin)
    (and found (= begin (match-end 0)))))


*** /u/src/gnuemacs-18.51/lisp/shell.el	Wed May 11 09:50:42 1988
--- /users/wolfgang/emacs18/patches/shell.el	Wed May 11 13:14:47 1988
***************
*** 1,3 ****
--- 1,22 ----
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;									     ;;
+ ;;	File:     shell.el						     ;;
+ ;;	Author:   Wolfgang Rupprecht					     ;;
+ ;;	Created:  Tue May 10 19:54:56 EDT 1988				     ;;
+ ;;	Contents: Gnuemacs Code with my hacks for a ksh-like sub-shell       ;;
+ ;;									     ;;
+ ;;	Copyright (c) 1988 1987 Wolfgang Rupprecht.			     ;;
+ ;;	All rights reserved.						     ;;
+ ;;									     ;;
+ ;;	$Log$								     ;;
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 
+ ;;;;
+ ;; this is a patched version of shell.el from gnuemacs 18.49, upgraded to 18.51
+ ;; patches are marked with '; wsr patch'
+ ;; -wolfgang rupprecht 9/15/87
+ ;;;;
+ 
  ;; Run subshell under Emacs
  ;; Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
  
***************
*** 84,94 ****
--- 103,119 ----
    (setq last-input-start (make-marker))
    (make-local-variable 'last-input-end)
    (setq last-input-end (make-marker))
+   (make-local-variable 'shell-history-list) ; wsr patch
+   (make-local-variable 'shell-history-index) ; wsr patch
+   (make-local-variable 'shell-last-search) ; wsr patch
    (run-hooks 'shell-mode-hook))
  
  (if shell-mode-map
      nil
    (setq shell-mode-map (make-sparse-keymap))
+   ; sparse keymaps have unordered key documentation in "C-hm" help window
+   ; this should make the C-c map a regular 128 entry map
+   (define-key shell-mode-map "\C-c" (make-keymap))
    (define-key shell-mode-map "\C-m" 'shell-send-input)
    (define-key shell-mode-map "\C-c\C-d" 'shell-send-eof)
    (define-key shell-mode-map "\C-c\C-u" 'kill-shell-input)
***************
*** 99,104 ****
--- 124,130 ----
    (define-key shell-mode-map "\C-c\C-o" 'kill-output-from-shell)
    (define-key shell-mode-map "\C-c\C-r" 'show-output-from-shell)
    (define-key shell-mode-map "\C-c\C-y" 'copy-last-shell-input))
+ 
  
  (defvar explicit-csh-args
    (if (eq system-type 'hpux)
***************
*** 142,148 ****
  	    (let ((symbol (intern-soft (concat "explicit-" name "-args"))))
  	      (if (and symbol (boundp symbol))
  		  (symbol-value symbol)
! 		'("-i")))))))
  
  (defun make-shell (name program &optional startfile &rest switches)
    (let ((buffer (get-buffer-create (concat "*" name "*")))
--- 168,175 ----
  	    (let ((symbol (intern-soft (concat "explicit-" name "-args"))))
  	      (if (and symbol (boundp symbol))
  		  (symbol-value symbol)
! 		'("-i"))))))
!   (if shell-read-history (shell-input-history-file))) ; wsr patch
  
  (defun make-shell (name program &optional startfile &rest switches)
    (let ((buffer (get-buffer-create (concat "*" name "*")))
***************
*** 151,157 ****
      (if proc (setq status (process-status proc)))
      (save-excursion
        (set-buffer buffer)
!       ;;    (setq size (buffer-size))
        (if (memq status '(run stop))
  	  nil
  	(if proc (delete-process proc))
--- 178,184 ----
      (if proc (setq status (process-status proc)))
      (save-excursion
        (set-buffer buffer)
!       (setq size (buffer-size))
        (if (memq status '(run stop))
  	  nil
  	(if proc (delete-process proc))
***************
*** 163,178 ****
  			  "EMACS=t"
  			  "-" (or program "sh") switches))
  	(cond ((stringp startfile)
! 	       ;;This is guaranteed to wait long enough
! 	       ;;but has bad results if the shell does not prompt at all
! 	       ;;	     (while (= size (buffer-size))
! 	       ;;	       (sleep-for 1))
! 	       ;;I hope 1 second is enough!
! 	       (sleep-for 1)
  	       (goto-char (point-max))
  	       (insert-file-contents startfile)
  	       (setq startfile (buffer-substring (point) (point-max)))
! 	       (delete-region (point) (point-max))
  	       (process-send-string proc startfile)))
  	(setq name (process-name proc)))
        (goto-char (point-max))
--- 190,206 ----
  			  "EMACS=t"
  			  "-" (or program "sh") switches))
  	(cond ((stringp startfile)
! 		(let ((cnt 3))		; wait up to 3 seconds for prompt
! 		  ; assume that prompt is unset if 3 seconds pass.
! 		  (while (and (= size (buffer-size))
! 			      (< 0 cnt))
! 		    (sit-for 1)
! 		    (setq cnt (1- cnt))))
  	       (goto-char (point-max))
  	       (insert-file-contents startfile)
  	       (setq startfile (buffer-substring (point) (point-max)))
! ; truth in advertising, show input region.
! ;	       (delete-region (point) (point-max)) ; -wsr
  	       (process-send-string proc startfile)))
  	(setq name (process-name proc)))
        (goto-char (point-max))
***************
*** 220,225 ****
--- 248,254 ----
      (error (funcall shell-set-directory-error-hook)))
    (let ((process (get-buffer-process (current-buffer))))
      (process-send-region process last-input-start last-input-end)
+     (shell-save-history)		; wsr patch
      (set-marker (process-mark process) (point))))
  
  ;;;  If this code changes (shell-send-input and shell-set-directory),
***************
*** 327,332 ****
--- 356,362 ----
  (defun kill-shell-input ()
    "Kill all text since last stuff output by the shell or its subjobs."
    (interactive)
+   (goto-char (point-max))		; slight bug fix. -wsr
    (kill-region (process-mark (get-buffer-process (current-buffer)))
  	       (point)))
  
***************
*** 337,342 ****
--- 367,374 ----
    (lisp-mode-commands inferior-lisp-mode-map)
    (define-key inferior-lisp-mode-map "\e\C-x" 'lisp-send-defun))
  
+ (require 'shellext) ; needs shell-mode-map and lisp-mode-map ; wsr patch
+ 
  (defvar inferior-lisp-program "lisp"
    "*Program name for invoking an inferior Lisp with `run-lisp'.")
  
***************
*** 393,398 ****
--- 425,433 ----
    (setq last-input-start (make-marker))
    (make-local-variable 'last-input-end)
    (setq last-input-end (make-marker))
+   (make-local-variable 'shell-history-list) ; wsr patch
+   (make-local-variable 'shell-history-index) ; wsr patch
+   (make-local-variable 'shell-last-search) ; wsr patch
    (run-hooks 'shell-mode-hook 'lisp-mode-hook))
  
  (defun run-lisp ()




Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
TEL: (617) 267-4365	UUCP:  mit-eddie!mgm.mit.edu!wolfgang