
(require (quote comint))

(provide (quote cmushell))

(put (quote shell-prompt-pattern) (quote variable-documentation) "Regexp to match prompts in the inferior shell.
Defaults to \"^[^#$%>]*[#$%>] *\", which works pretty well.
This variable is used to initialise comint-prompt-regexp in the 
shell buffer.

This is a fine thing to set in your .emacs file.")

(defvar shell-popd-regexp "popd" "\
*Regexp to match subshell commands equivalent to popd.")

(defvar shell-pushd-regexp "pushd" "\
*Regexp to match subshell commands equivalent to pushd.")

(defvar shell-cd-regexp "cd" "\
*Regexp to match subshell commands equivalent to cd.")

(defvar explicit-shell-file-name nil "\
*If non-nil, is file name to use for explicitly requested inferior shell.")

(defvar explicit-csh-args (if (eq system-type (quote hpux)) (quote ("-i" "-T")) (quote ("-i"))) "\
*Args passed to inferior shell by M-x cmushell, if the shell is csh.
Value is a list of strings, which may be nil.")

(defvar cmushell-dirstack nil "\
List of directories saved by pushd in this buffer's shell.")

(defvar cmushell-dirstack-query "dirs" "\
Command used by shell-resync-dirlist to query shell.")

(defvar cmushell-mode-map (quote nil))

(cond ((not cmushell-mode-map) (setq cmushell-mode-map (full-copy-sparse-keymap comint-mode-map)) (define-key cmushell-mode-map "" (quote comint-dynamic-complete)) (define-key cmushell-mode-map "" (quote comint-dynamic-list-completions))))

(defvar cmushell-mode-hook (quote nil) "\
*Hook for customising cmushell mode")

(defun cmushell-mode nil "\
Major mode for interacting with an inferior shell.
Return after the end of the process' output sends the text from the 
    end of process to the end of the current line.
Return before end of process output copies rest of line to end (skipping
    the prompt) and sends it.
M-x send-invisible reads a line of text without echoing it, and sends it to
    the shell.

If you accidentally suspend your process, use \\[comint-continue-subjob]
to continue it.

cd, pushd and popd commands given to the shell are watched by Emacs to keep
this buffer's default directory the same as the shell's working directory.
M-x dirs queries the shell and resyncs Emacs' idea of what the current 
    directory stack is.
M-x dirtrack-toggle turns directory tracking on and off.

\\{cmushell-mode-map}
Customisation: Entry to this mode runs the hooks on comint-mode-hook and
cmushell-mode-hook (in that order).

Variables shell-cd-regexp, shell-pushd-regexp and shell-popd-regexp are used
to match their respective commands." (interactive) (byte-code "ƈ 	ˉ̉!!Ɖ!ȉω	!" [comint-prompt-regexp shell-prompt-pattern major-mode mode-name cmushell-mode-map cmushell-dirstack nil cmushell-dirtrackp t comint-input-sentinel comint-mode cmushell-mode "CMU shell" use-local-map make-local-variable cmushell-directory-tracker run-hooks cmushell-mode-hook] 6))

(defun cmushell nil "\
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.
If a file ~/.emacs_SHELLNAME exists, it is given as initial input
 (Note that this may lose due to a timing error if the shell
  discards input when it starts up.)
The buffer is put in cmushell-mode, giving commands for sending input
and controlling the subjobs of the shell.  See cmushell-mode.
See also variable shell-prompt-pattern.

The shell file name (sans directories) is used to make a symbol name
such as `explicit-csh-arguments'.  If that symbol is a variable,
its value is used as a list of arguments when invoking the shell.
Otherwise, one argument `-i' is passed to the shell.

(Type \\[describe-mode] in the shell buffer for a list of commands.)" (interactive) (byte-code "ň!?K 	 ! ! !
P
Q!!5 < !D JE %q ,!" [prog explicit-shell-file-name name startfile xargs-name nil comint-check-proc "*cmushell*" getenv "ESHELL" "SHELL" "/bin/sh" file-name-nondirectory "~/.emacs_" intern-soft "explicit-" "-args" apply make-comint "cmushell" file-exists-p boundp ("-i") cmushell-mode switch-to-buffer] 13))

(defun cmushell-front-match (regexp str start) (byte-code "	
#=" [start regexp str string-match] 5))

(defun cmushell-directory-tracker (str) "\
Tracks cd, pushd and popd commands issued to the shell.
This function is called on each input passed to the shell.
It watches for cd, pushd and popd commands and sets the buffer's
default directory to track these commands.

You may toggle this tracking on and off with M-x dirtrack-toggle.
If emacs gets confused, you can resync with the shell with M-x dirs.

See variables shell-cd-regexp, shell-pushd-regexp, and shell-popd-regexp." (byte-code "? 	\"!	
# !> 	
#0 !> 	
#> !*" [cmushell-dirtrackp str bos x nil shell-popd-regexp shell-pushd-regexp shell-cd-regexp string-match "^\\s *" match-end 0 cmushell-match-cmd-w/optional-arg cmushell-process-popd cmushell-process-pushd cmushell-process-cd] 10))

(defun cmushell-match-cmd-w/optional-arg (cmd str start) (byte-code "	
#- !	# ʂ, 	#+ 	!!O, )" [cmd str start eoc t nil cmushell-front-match match-end 0 "\\s *\\(;\\|$\\)" "" "\\s +\\([^ 	;]+\\)\\s *\\(;\\|$\\)" match-beginning 1] 9))

(defun cmushell-process-popd (arg) (byte-code "	G! ǂ 	! 
GWD U' ʏA 
BZ\"AA\"A *G !)" [num arg cmushell-dirstack ds nil cell zerop 0 cmushell-extract-num (byte-code "@!A " [cmushell-dirstack cd cmushell-dirstack-message] 3) ((error (byte-code "!" [message "Couldn't cd."] 2))) nthcdr 1 rplacd cmushell-dirstack-message message "Bad popd."] 7))

(defun cmushell-process-cd (arg) (byte-code "" [nil (byte-code "G! ! ! " [arg cd zerop getenv "HOME" cmushell-dirstack-message] 5) ((error (byte-code "!" [message "Couldn't cd."] 2)))] 3))

(defun cmushell-process-pushd (arg) (byte-code "G! ͏U !	L 	
GV# !I 
BG	\"	Z!\"!\"Տ-T 	׏))" [arg num cmushell-dirstack ds default-directory dslen front back new-ds old-wd zerop nil (byte-code " 
@!	AB ) !" [cmushell-dirstack old default-directory cd cmushell-dirstack-message message "Directory stack empty."] 4) ((message (byte-code "" ["Couldn't cd."] 1))) cmushell-extract-num message "Directory stack not that deep." nthcdr reverse append (byte-code "@!A " [new-ds cmushell-dirstack cd cmushell-dirstack-message] 3) ((error (byte-code "!" [message "Couldn't cd."] 2))) (byte-code "!
	B " [arg cmushell-dirstack old-wd cd cmushell-dirstack-message] 3) ((error (byte-code "!" [message "Couldn't cd."] 2)))] 11))

(defun cmushell-extract-num (str) (byte-code "\"
 !" [str string-match "^\\+[1-9][0-9]*$" string-to-int] 3))

(defun cmushell-dirtrack-toggle nil "\
Turn directory tracking on and off in a cmushell buffer." (interactive) (byte-code "? Ă \"" [cmushell-dirtrackp nil message "directory tracking %s." "ON" "OFF"] 3))

(fset (quote dirtrack-toggle) (quote cmushell-dirtrack-toggle))

(defun cmushell-resync-dirs nil "\
Resync the buffer's idea of the current directory stack.
This command queries the shell with the command bound to 
cmushell-dirstack-query (default \"dirs\"), reads the next
line output and parses it to form the new directory stack.
DON'T issue this command unless the buffer is at a shell prompt.
Also, note that if some other subprocess decides to do output
immediately after the query, its output will be taken as the
new directory stack -- you lose. If this happens, just do the
command again." (interactive) (byte-code "Ȉp!!	b
cc!
\"\"	`\"`c!!?@ !b/ )	b!!!Z\"GW #!!OB!] !ݏ),*" [proc pmark cmushell-dirstack-query pt dl dl-len ds i nil get-buffer-process process-mark "
" sit-for 0 comint-send-string set-marker backward-char 1 looking-at ".+
" accept-process-output delete-char buffer-substring match-beginning match-end string-match "\\s *\\(\\S +\\)\\s *" reverse (byte-code "@!A " [ds cmushell-dirstack cd cmushell-dirstack-message] 3) ((error (byte-code "!" [message "Couldn't cd."] 2)))] 21))

(fset (quote dirs) (quote cmushell-resync-dirs))

(defun cmushell-dirstack-message nil (byte-code "
B	? 	@!\"\"# !OP\". ЉQ	A) !*" [msg ds default-directory cmushell-dirstack dir "" string-match format "^%s\\(/\\|$\\)" getenv "HOME" "~/" match-end 0 nil string-equal "~" " " message] 9))

(defvar cmushell-load-hook nil "\
This hook is run when cmushell is loaded in.
This is a good place to put keybindings.")

(run-hooks (quote cmushell-load-hook))
