[comp.emacs] cmushell-mode [was: Re: comint

scott@grlab.UUCP (Scott Blachowicz) (02/21/90)

Regarding comint (generally) and gdb/comint; shivers@cs.cmu.edu (Olin Shivers) writes:
> Hello, Jordan. Hope all is well. Let me address a few general points 
> before I get to your question.
> - I've got several small upgrades to comint: improved M-p & M-n commands,
>   improved filename completion, and a new hook someone sent me that
>   is called on text before you submit it to the process (for processes
>   that might require funny input conventions). I also have some improved
>   directory tracking code that someone sent me. As soon as I have the time,
>   I'll merge in the new stuff and mail it out.  
Is it possible to have the shell mode re-sync its current-directory on
a pwd command? Either by recognizing that a pwd command was typed or
by a key-binding that somehow figures it out (send a pwd command and
get the response)? Maybe there could be a regexp that describes what a
"pwd" command will look like that gets matched against the command.
Now, I don't know enough to know how possible it would be to grab the
command's output (if it can even be reliably identified).

Does the new directory tracking stuff allow me to say "cd -" to "goto
the previous directory"? My ksh allows that (actually, I think it's a
bunch of functions that get loaded up that do it).

I've noticed a few other things...
  -Could it recognize a "Password:" prompt at the beginning of a line
   and not echo the chars? or is there a better way to get a
   super-user shell?

  -A lot of times, when I run an interactive command I start getting
   commands echoed back at me, and sometimes "^M" at the end of each
   line... Would this be because the command is doing some stty/ioctl
   commands? Anyone know of the magic incantation to give stty to
   correct things?

--
Scott Blachowicz                E-mail:  scott@grlab.UUCP
USPS:  Graphicus                 ..or..  ...!hpubvwa!grlab!scott
       150 Lake Str S, #206     VoicePh: 206/828-4691
       Kirkland, WA 98033       FAX:     206/828-4236

jr@bbn.com (John Robinson) (02/26/90)

In article <SCOTT.90Feb21103559@grlab.grlab.UUCP>, scott@grlab (Scott Blachowicz) writes:
>  -Could it recognize a "Password:" prompt at the beginning of a line
>   and not echo the chars? or is there a better way to get a
>   super-user shell?

(Another idea about how to supress echoes - cause a signal in emacs
when the tty/pty has switched modes, and hang a function on that to
toggle echoing (or enable non-echoing reading) when the process does
stty -echo.)

In reverse order; here's a function I use to execute one command as
super-user.  Modeled on shell-command (M-!).  This version collects
the password with echoing (if you type slowly :-); it could be
modified to use one of the read-no-echo functions, like the one in the
second lisp bit below.

(defun su-command (password command)
  "Prompt for root password and a command, then do the latter as root."
;;; (don't say "Password: "; it might give you away on a net.)
  (interactive "sMagic cookie: \nsCommand: ")
  (let ((buffer (get-buffer-create "*Shell Command Output*"))
        proc)
    (save-excursion
          (set-buffer buffer)
          (erase-buffer))
    (setq proc (start-process "su-emacs" buffer "/bin/su"
                              "-c" command))
    (if (save-excursion
          (set-buffer buffer)
          (goto-char (point-min))
          (while (not (looking-at "Password:"))
            (accept-process-output proc)
            (goto-char (point-min)))
          (erase-buffer)
          (send-string proc (concat password "\n"))
          (while (not (looking-at "\n"))
            (accept-process-output proc)
            (goto-char (point-min)))
          (delete-char 1)
          (while (not (equal (process-status proc) 'exit))
            (accept-process-output))
          (> (buffer-size) 0))
        (set-window-start (display-buffer buffer) 1)
      (message "(Command completed with no output)"))))
;;; suggested binding (su prompt is #):
;;; (global-set-key "\e#" 'su-command)

Now, for part two, Silver (Andy Gaynor) posted this a while back:
========8<----------------------------------------------------------------
(provide 'shell-filter)

;;Date:         Fri, 15 Dec 89 23:22:36 GMT
;;Reply-To:     gaynor@topaz.rutgers.edu
;;From:         Silver <paul.rutgers.edu!gaynor%RUTGERS.EDU>
;;Subject:      Giving shell filters one last kick...

;; When logging in remotely, you might want to give the command "stty -echo" to
;; suppress the echoing of commands as they're executed.  For tcsh, you may
;; also want to unset editmode and/or filec.  Up to you, though...

;; The regexp is a little convoluted, but I think it covers most of the bases.
(defvar shell-filter-password-prompt "\\<passw\\(or\\)?d[\ \t]*[:>][\ \t]*\\'"
"Regular expression used to determine whether shell output contains a request
for a password.  The successful candidate will match the end of the buffer,
handle whitespace appropriately, and various convolutions of `password'.  The
ambient value of case-fold-search is non-nil during matching.")

(defun read-string-no-echo (&optional prompt)
"Read and return a string without echoing it.  Newline and return characters
terminate input.  If optional PROMPT is non-nil, it is displayed and the cursor
placed in the minibuffer while reading.  \(Warning: view-lossage/recent-keys
can access the last 100 characters typed.\)"
  (interactive)
  (save-window-excursion
    (let ((echo-keystrokes 0)
          (string "")
          char)
      (if prompt
        (progn (select-window (minibuffer-window))
               (set-window-buffer (selected-window)
                                  (get-buffer-create " *Temporary*"))
               (erase-buffer)
               (insert prompt)))
      ;; Grossly inefficient.  BFD.
      (while (not (memq (setq char (read-char)) '(?\r ?\n)))
        (setq string (concat string (char-to-string char))))
      string)))

(defun shell-filter-read-password ()
"Read a password in-line (without display, of course) and return it."
  (read-string-no-echo))

(defun shell-filter-nuke-1    () (delete-char 1))
(defun shell-filter-ding      () (delete-char 1) (ding 'continue))
(defun shell-filter-backspace () (delete-char 1) (delete-char (if (eq ?_
 (preceding-char)) -1 1)))

;; I would have done this by regexp instead of character, but I think that this
;; would be putting more computation and effort than the task warrants.
(defvar shell-filter-specials-alist
  '((?\C-m . shell-filter-nuke-1)
    (?\C-l . shell-filter-nuke-1)
    (?\C-g . shell-filter-ding)
    (?\C-h . shell-filter-backspace))
"Alist of (CHARACTER . ACTION).  When CHARACTER is encountered in shell output,
call ACTION with no parameters.")

(defun shell-filter (process string)
"Output filter for shell-mode buffers.  See shell-filter-specials-alist for
information about special character handling.  See shell-filter-password-prompt
and shell-filter-read-password for information about password handling."
  (save-excursion
    (set-buffer (process-buffer process))
    (goto-char (marker-position (process-mark process)))
    (let ((begin (point))
          (end (progn (insert-before-markers string) (point)))
          (case-fold-search t)
          (specials (concat "^" (mapconcat (function (lambda (el)
                                                       (char-to-string (car
 el))))
                                           shell-filter-specials-alist ""))))
      (goto-char begin)
      ;; Alternatively, things could be based around re-search-foward.  There's
      ;; no need for the added overhead, imho.
      (while (progn (skip-chars-forward specials end) (< (point) end))
        (funcall (cdr (assoc (following-char) shell-filter-specials-alist))))
      ;; It might be more `correct' to match against string instead of the buffer.
      (if (re-search-backward shell-filter-password-prompt begin t)
        (progn (goto-char (match-end 0))
               (process-send-string process (concat (shell-filter-read-password)
 "\n")))))))

;; RU's site-init contains a function named add-hook.  I don't know if it's
;; standard, but its intent is fairly obvious.
(setq shell-mode-hook
      (function (lambda ()
		  ;; Uncomment this if you want shells to die easily.
		  ;; (process-kill-without-query (get-buffer-process (current-buffer)))
		  (set-process-filter (get-buffer-process (current-buffer))
                                          (function shell-filter)))))
========8<----------------------------------------------------------------
/jr, nee John Robinson     Life did not take over the globe by combat,
jr@bbn.com or bbn!jr          but by networking -- Lynn Margulis