[gnu.emacs.bug] comint mode and cmushell mode

kayvan@mrspoc.transact.com (Kayvan Sylvan) (09/08/89)

I was just looking at the CMU Shell and comint sources for the purpose of
adding a hook to the directory tracker that would allow a "synchronization" to
occur upon input of the "pwd" command.

I got tired of having my Emacs lose track of what directory my shell buffer is
in. I figured it would be easy but it does not seem so. Emacs would have to
read the output from the shell when pwd was invoked and then do a cd to that
directory.

Anyone have any insight on this?

			---Kayvan

Kayvan Sylvan @ Transact Software, Inc. -*-  Los Altos, CA (415) 961-6112
Internet: kayvan@Transact.COM -*- UUCP: ...!{apple,pyramid,mips}!mrspoc!kayvan

peck@SUN.COM (Jeff Peck) (09/08/89)

Here are diffs for 3 additions to cmushell/comint
1. allow customized comint-input-send function 
  (i needed this for a "psh" shell mode)

2. give arbitrary names to cmushell buffers (with arg)

3. handle: pushd +2  and resync directories
    
Enjoy!

*** comint.el.~1~	Tue Jun 27 14:32:53 1989
--- comint.el	Fri Jun 30 18:08:33 1989
***************
*** 94,99 ****
--- 94,100 ----
  ;;;     comint-get-old-input    - function     Hooks for specific 
  ;;;     comint-input-sentinel   - function         process-in-a-buffer
  ;;;     comint-input-filter     - function         modes.
+ ;;;	comint-input-send	- function
  (defvar comint-prompt-regexp "^"
    "Regexp to recognise prompts in the inferior process.
  Defaults to \"^\", the null string at BOL.
***************
*** 129,134 ****
--- 130,141 ----
  Only inputs answering true to this function are saved on the input
  history list. Default is to save anything that isn't all whitespace")
  
+ (defvar comint-input-send (function comint-send-string)
+   "Function to actually send to PROCESS the STRING.
+ usually this is just 'comint-send-string, but if your mode needs to 
+ massage the input string, this is your hook.
+ comint-send-string just uses process-send-string and also sends a newline.")
+ 
  (defvar comint-mode-hook '()
    "Called upon entry into comint-mode")
  
***************
*** 177,182 ****
--- 184,190 ----
      (make-variable-buffer-local 'comint-get-old-input)
      (make-variable-buffer-local 'comint-input-sentinel)
      (make-variable-buffer-local 'comint-input-filter)  
+     (make-variable-buffer-local 'comint-input-send)
      (run-hooks 'comint-mode-hook)
      ;Do this after the hook so the user can mung INPUT-RING-SIZE w/his hook.
      ;The test is so we don't lose history if we run comint-mode twice in
***************
*** 477,482 ****
--- 485,496 ----
      (if p (goto-char p)
  	(error "No match"))))
  
+ (defun comint-send-string (proc string)
+   "Called by comint-send-input via the variable comint-input-send.
+ This is uses process-send-string to send the input and a newline."
+   (process-send-string proc string)
+   (process-send-string proc "\n"))
+ 
  (defun comint-send-input () 
    "Send input to process.  After the process output mark, sends all text
  from the process mark to point as input to the process.  Before the
***************
*** 486,491 ****
--- 500,507 ----
  case, value of variable comint-input-sentinel is called on the input before
  sending it.  The input is entered into the input history ring, if value of
  variable comint-input-filter returns T when called on the input.
+ The sending is actually done by funcalling the local value of comint-input-send.
+ This is usually uses process-send-string to send the input and a newline.
  
  comint-get-old-input, comint-input-sentinel, and comint-input-filter are chosen
  according to the command interpreter running in the buffer. E.g.,
***************
*** 519,526 ****
  	  (insert ?\n)
  	  (if (funcall comint-input-filter input) (ring-insert input-ring input))
  	  (funcall comint-input-sentinel input)
! 	  (process-send-string proc input)
! 	  (process-send-string proc "\n")
  	  (set-marker (process-mark proc) (point))
  	  (set-marker comint-last-input-end (point))))))
  
--- 535,543 ----
  	  (insert ?\n)
  	  (if (funcall comint-input-filter input) (ring-insert input-ring input))
  	  (funcall comint-input-sentinel input)
! 	  (funcall comint-input-send proc input)
! 	  ;;(process-send-string proc input)
! 	  ;;(process-send-string proc "\n")
  	  (set-marker (process-mark proc) (point))
  	  (set-marker comint-last-input-end (point))))))
  
*** cmushell.el.~1~	Tue Jun 27 14:31:03 1989
--- cmushell.el	Wed Aug 23 18:10:15 1989
***************
*** 50,56 ****
  ;;; Maybe I should ensure the process mark is in the window when I send
  ;;; text to the process? Switch selectable?
  
! (require 'comint)
  (provide 'cmushell)
  
  ;; YOUR .EMACS FILE
--- 50,57 ----
  ;;; Maybe I should ensure the process mark is in the window when I send
  ;;; text to the process? Switch selectable?
  
! (require 'comint "local/comint/comint")
! (require 'cl)
  (provide 'cmushell)
  
  ;; YOUR .EMACS FILE
***************
*** 270,275 ****
--- 271,279 ----
    (interactive)
    (comint-mode)
    (setq comint-prompt-regexp inferior-lisp-prompt)
+   (setq comint-get-old-input (function lisp-get-old-input))
+   (setq comint-input-filter (function lisp-input-filter))
+   (setq comint-input-sentinel 'ignore)
    (setq major-mode 'cmulisp-mode)
    (setq mode-name "CMU Lisp")
    (setq mode-line-process '(": %s"))
***************
*** 277,285 ****
        (lisp-mode-variables)    ; This is right for 18.49  
        (lisp-mode-variables t)) ; This is right for 18.50
    (use-local-map cmulisp-mode-map)    ;c-c k for "kompile" file
-   (setq comint-get-old-input (function lisp-get-old-input))
-   (setq comint-input-filter (function lisp-input-filter))
-   (setq comint-input-sentinel 'ignore)
    (run-hooks 'cmulisp-mode-hook))
  
  (defun lisp-get-old-input ()
--- 281,286 ----
***************
*** 529,539 ****
    (run-hooks 'cmushell-mode-hook))
  
  
! (defun cmushell ()
!   "Run an inferior shell, with I/O through buffer *cmushell*.
  If buffer exists but shell process is not running, make new shell.
  If buffer exists and shell process is running, 
!  just switch to buffer *cmushell*.
  Program used comes from variable explicit-shell-file-name,
   or (if that is nil) from the ESHELL environment variable,
   or else from SHELL if there is no ESHELL.
--- 530,540 ----
    (run-hooks 'cmushell-mode-hook))
  
  
! (defun cmushell (&optional bname)
!   "Run an inferior shell, with I/O through buffer *NAME* (\"*cmushell*\").
  If buffer exists but shell process is not running, make new shell.
  If buffer exists and shell process is running, 
!  just switch to buffer *NAME*.
  Program used comes from variable explicit-shell-file-name,
   or (if that is nil) from the ESHELL environment variable,
   or else from SHELL if there is no ESHELL.
***************
*** 551,571 ****
  
  \(Type \\[describe-mode] in the shell buffer for a list of commands.)"
    (interactive)
!   (cond ((not (comint-check-proc "*cmushell*"))
! 	 (let* ((prog (or explicit-shell-file-name
! 			  (getenv "ESHELL")
! 			  (getenv "SHELL")
! 			  "/bin/sh"))		     
! 		(name (file-name-nondirectory prog))
! 		(startfile (concat "~/.emacs_" name))
! 		(xargs-name (intern-soft (concat "explicit-" name "-args"))))
! 	   (set-buffer (apply 'make-comint "cmushell" prog
! 			      (if (file-exists-p startfile) startfile)
! 			      (if (and xargs-name (boundp xargs-name))
! 				  (symbol-value xargs-name)
! 				  '("-i"))))
! 	   (cmushell-mode))))
!   (switch-to-buffer "*cmushell*"))
  
  
  ;;; Directory tracking
--- 552,574 ----
  
  \(Type \\[describe-mode] in the shell buffer for a list of commands.)"
    (interactive)
!   (unless bname (setq bname "cmushell"))
!   (let ((bufname (concat "*" bname "*")))
!     (cond ((not (comint-check-proc bufname))
! 	   (let* ((prog (or explicit-shell-file-name
! 			    (getenv "ESHELL")
! 			    (getenv "SHELL")
! 			    "/bin/sh"))		     
! 		  (name (file-name-nondirectory prog))
! 		  (startfile (concat "~/.emacs_" name))
! 		  (xargs-name (intern-soft (concat "explicit-" name "-args"))))
! 	     (set-buffer (apply 'make-comint bname prog
! 				(if (file-exists-p startfile) startfile)
! 				(if (and xargs-name (boundp xargs-name))
! 				    (symbol-value xargs-name)
! 				    '("-i"))))
! 	     (cmushell-mode))))
!     (switch-to-buffer bufname)))
  
  
  ;;; Directory tracking
***************
*** 651,667 ****
  	       ;; The command came with an argument. If pushd, push 
  	       ;; the current directory (DEFAULT-DIRECTORY) on the stack.
  	       ;; In either case, cd to the argument.
! 	       (let ((dir (progn (string-match "[^ \t\;]*" str i) ; match dir
! 				 (expand-file-name
! 				  (substitute-in-file-name
! 				   (substring str i (match-end 0)))))))
  		 (cond ((file-directory-p dir)
  			(if (not cd-p)	; push the current directory
! 			    (setq shell-directory-stack
! 				  (cons default-directory
! 					shell-directory-stack)))
! 			(cd dir)))))))))
  
  
  ;;; Interfacing to client packages (and converting them)
  ;;;============================================================================
--- 654,706 ----
  	       ;; The command came with an argument. If pushd, push 
  	       ;; the current directory (DEFAULT-DIRECTORY) on the stack.
  	       ;; In either case, cd to the argument.
! 	       (let* ((arg (progn (string-match "[^ \t\;]*" str i) ; match dir
! 				  (substring str i (match-end 0))))
! 		      (dir (expand-file-name (substitute-in-file-name arg))))
  		 (cond ((file-directory-p dir)
  			(if (not cd-p)	; push the current directory
! 			    (push default-directory shell-directory-stack))
! 			(cd dir))
! 		       ((string-match "+\\([0-9]+\\)" arg 0)
! 			(setq arg (car (read-from-string arg (match-beginning 1) (match-end 1))))
! 			(when (<= arg (length shell-directory-stack))
! 			  (do ((l (list default-directory))
! 			       (i (1- arg) (1- i)))
! 			      ((<= i 0)
! 			       (setq shell-directory-stack (append shell-directory-stack (reverse l)))
! 			       (cd (setq default-directory (pop shell-directory-stack)))
! 			       )
! 			    (push (pop shell-directory-stack) l)
! 			    ))))))))))
  
+ (defun csh-directory-sync ()
+   "Re synchronizes comints internal shell-directory-stack with the csh version."
+   (interactive)
+   (save-excursion
+     (goto-char (point-max))
+     (process-send-string (get-buffer-process (current-buffer)) "dirs\n")
+     (shell-dir-sync
+      (buffer-substring (progn (forward-line -1) (comint-bol nil) (point))
+ 		       (progn (end-of-line) (point))))
+     (message "%s" default-directory)
+     ))
+ 
+ (defun csh-dir-sync (dirs)
+   (do* ((dirname "[ \t]*\\([^ \t\;]*\\)[ \t]*")
+ 	(l nil)
+ 	(beg0 (string-match dirname dirs 0) (string-match dirname dirs end0))
+ 	(end0 (match-end 0) (match-end 0)))
+       ((= beg0 end0)
+        (setq l (reverse l))
+        (setq shell-directory-stack (cdr l))
+        (setq default-directory (car l))
+        )
+     (setq l (cons (expand-file-name
+ 		   (substitute-in-file-name
+ 		    (substring dirs (match-beginning 1) (match-end 1)))) l))
+     ))
+ 
+     
  
  ;;; Interfacing to client packages (and converting them)
  ;;;============================================================================