[comp.windows.x] shell-util.el

conor@goose.UUCP (Conor Rafferty) (12/04/87)

Expires:

References:

Sender:

Followup-To:

Distribution:


A new version of gnumacs just came up for me with a minimum of bother.
To express my gratitude :) I have collected a few little hacks I use
to make interaction with subshells more convenient. Particularly subshells
containing dbx. The first hack, called shell-repeat, takes an expression like
    print pt[nd[0:2]->pt]->cord
and turns it into
    print pt[nd[0]->pt]->cord; print pt[nd[1]->pt]->cord; print pt[nd[2]->pt]->cord

Vi lovers have said it's almost enough to convert them :-)

The second hack is called just-like-csh and does what you would expect.
!!	repeats the previous command
!a	repeats the previous command starting with an a
!?abc	repeats the previous command containing abc

just-like-csh relies on shell and telnet windows copying user input
lines into a buffer called *history*. That requires a minor change
in both shell.el and telnet.el.

------------------------------Changes to shell.el------------------------------
*** /u2/conor/bin/shell.el	Thu Dec  3 22:30:14 1987
--- /u2/conor/src/emacs/lisp/shell.el	Fri Aug 14 14:55:08 1987
***************
*** 216,228 ****
  	  (goto-char last-input-start)
  	  (shell-set-directory))
        (error (funcall shell-set-directory-error-hook)))
!   (let ((process (get-buffer-process (current-buffer))) command-copy) ;csr{
      (process-send-region process last-input-start last-input-end)
!     (set-marker (process-mark process) (point))
!     (setq command-copy (buffer-substring last-input-start last-input-end))
!     (set-buffer (get-buffer-create "*history*"))
!     (end-of-buffer)
!     (insert command-copy)))		;csr}
  ;;;  If this code changes (shell-send-input and shell-set-directory),
  ;;;  the customization tutorial in
  ;;;  info/customizing-tutorial must also change, since it explains this
--- 216,225 ----
  	  (goto-char last-input-start)
  	  (shell-set-directory))
        (error (funcall shell-set-directory-error-hook)))
!   (let ((process (get-buffer-process (current-buffer))))
      (process-send-region process last-input-start last-input-end)
!     (set-marker (process-mark process) (point))))
! 
  ;;;  If this code changes (shell-send-input and shell-set-directory),
  ;;;  the customization tutorial in
  ;;;  info/customizing-tutorial must also change, since it explains this


------------------------------Changes to telnet.el------------------------------
*** /u2/conor/bin/telnet.el	Thu Dec  3 22:31:00 1987
--- /u2/conor/src/emacs/lisp/telnet.el	Tue Sep  1 10:28:14 1987
***************
*** 24,31 ****
  ;;to eval current expression.  Also to try to send escape keys correctly.
  ;;essentially we'll want the rubout-handler off.
  
- (provide 'telnet)
- 
  (defvar telnet-new-line "\r")
  (defvar telnet-mode-map nil)
  (defvar telnet-prompt-pattern "^[^#$%>]*[#$%>] *")
--- 24,29 ----
***************
*** 97,106 ****
  		 (t (setq telnet-count (1+ telnet-count)))))))
  
  (defun telnet-filter (proc string)
-   (let ((move-point-p))			;csr to avoid underfoot movement
    (save-excursion
      (set-buffer (process-buffer proc))
-     (if (eq (point) (point-max)) (setq move-point-p t))	;csr
      (goto-char (point-max))
      (let ((now (point)))
        (insert string)
--- 95,102 ----
***************
*** 112,122 ****
  	     (marker-position last-input-start)
  	     telnet-remote-echoes)
  	(delete-region last-input-start last-input-end)))
!   (if (and				;csr
! 	move-point-p			;csr
! 	(eq (process-buffer proc)
! 	    (current-buffer)))
!       (goto-char (point-max)))))
  
  (defun delete-char-or-send-eof (arg killp)
    "At end of buffer, send eof to subshell.  Otherwise delete character."
--- 108,116 ----
  	     (marker-position last-input-start)
  	     telnet-remote-echoes)
  	(delete-region last-input-start last-input-end)))
!   (if (eq (process-buffer proc)
! 	  (current-buffer))
!       (goto-char (point-max))))
  
  (defun delete-char-or-send-eof (arg killp)
    "At end of buffer, send eof to subshell.  Otherwise delete character."
***************
*** 150,164 ****
        (move-marker last-input-end (point))))
    (save-excursion
      (goto-char last-input-start)
!     (shell-set-directory)
!     (let ((process (get-buffer-process (current-buffer))) copy-command) ;csr{
        (send-region process last-input-start last-input-end)
        (if (not copied) (send-string process telnet-new-line))
!       (set-marker (process-mark process) (point))
!       (setq copy-command (buffer-substring last-input-start last-input-end))
!       (set-buffer (get-buffer-create "*history*"))
!       (goto-char (point-max))
!       (insert copy-command "\n"))))) ;csr}
  
  (defun telnet (arg)
    "Open a network login connection to host named HOST (a string).
--- 144,153 ----
        (move-marker last-input-end (point))))
    (save-excursion
      (goto-char last-input-start)
!     (let ((process (get-buffer-process (current-buffer))))
        (send-region process last-input-start last-input-end)
        (if (not copied) (send-string process telnet-new-line))
!       (set-marker (process-mark process) (point))))))
  
  (defun telnet (arg)
    "Open a network login connection to host named HOST (a string).

------------------------------shell-util.el------------------------------
; load this explicitly
(require 'shell)
(require 'telnet)
(require 'blisp)



;----------
;Extra history stuff
;----------

(defvar last-shell nil "shell buffer to copy input to")
(defvar history-map nil "map inside history buffer")

;define the history buffer
(save-excursion
  (set-buffer (get-buffer-create "*history*"))
  (if (not history-map) (setq history-map (make-sparse-keymap)))
  (define-key history-map "\C-m" 'copy-history-to-shell)
  (use-local-map history-map)
)

;how you go back to shells
(defun copy-history-to-shell ()
  (interactive)
  (let ((line (buffer-line)))
    (or last-shell (error "no last shell defined?!"))
    (switch-to-window last-shell)
    (goto-char (point-max))
    (insert line)))

;define how you get there from shells
(define-key shell-mode-map "\e!" 'switch-to-history)
(define-key shell-mode-map "!" 'just-like-csh)
(define-key telnet-mode-map "\e!" 'switch-to-history)
(define-key telnet-mode-map "!" 'just-like-csh)

(defun switch-to-history ()
  (interactive)
  (setq last-shell (current-buffer))
  (switch-to-buffer "*history*"))


(defun just-like-csh ()
  (interactive)
  (setq last-shell (current-buffer))
  (let ((s (read-string "Repeat: ")))
    (set-buffer "*history*")
    (save-excursion
      (goto-char (point-max))
      (cond
	((or (zerop (length s)) (equal (aref s 0) ?!))
	 (re-search-backward "^."))
	((equal (aref s 0) ??)
	 (search-backward (substring s 1)))
	(t
	  (re-search-backward (concat "^" (regexp-quote s)))))
      (copy-history-to-shell))))


;----------
;random
;----------
(define-key shell-mode-map "\C-x9" 'shell-repeat)
(define-key telnet-mode-map "\C-x9" 'shell-repeat)

(defun shell-repeat ()
"Expands arithmetic loops. ``p pt[nd[0:2]->pt]'' becomes
``p pt[nd[0]->pt]->cord;p pt[nd[1]->pt]->cord;p pt[nd[2]->pt]->cord;''
This makes unprogrammable debuggers like dbx a little more tolerable."
  (interactive)
  (let (start-user end-user line count lo hi lsp last-insert)
    (if (not (eobp))
	(message "Only works at end of buffer")
      (setq start-user (process-mark (get-buffer-process (current-buffer))))
      (goto-char start-user)
      ;Someday, add , in the expansion
      (re-search-forward "\\([0-9]+\\):\\([0-9]+\\)")
      (setq lo (buffer-substring (match-beginning 1) (match-end 1)))
      (setq hi (buffer-substring (match-beginning 2) (match-end 2)))
      (setq lo (string-to-int lo))
      (setq hi (string-to-int hi))
      (if (< hi lo) (error "first number must be less than second"))
      (end-of-line)
      (setq end-user (point))
      (setq line (buffer-substring start-user end-user))
      (kill-region start-user end-user)

      ;Get exciting screen action because replace-regexp calls push-mark
      (setq count lo)
      (setq lsp start-user)
      (while (<= count hi)
	(goto-char (point-max));
	(setq last-insert (point))

	; Hack to avoid sending > 200 chars per line to send-region
	(if (> (- last-insert lsp) 200) (progn (insert "\n") (setq lsp last-insert)))
	(insert line)
	(goto-char last-insert)
	(replace-regexp "[0-9]+:[0-9]+" (int-to-string count))
	(goto-char (point-max))
	(insert ";")
	(setq count (+ count 1)))
      (set-buffer "*history*")
      (end-of-buffer)
      (insert line "\n"))))

------------------------------blisp.el------------------------------
; some basic lisp functions
; I repeat again and again.
(provide 'blisp)

(defun lose-buffer (&optional bufname)
  "Do what bury-buffer only promises to do"
  (interactive)
  (if (not bufname)
      (setq bufname (current-buffer)))
  (bury-buffer bufname)
  (switch-to-buffer (other-buffer (current-buffer))))

(defun switch-to-window (name)
  "select the window of the named BUFFER. If none, get one."
  (let* ((bbb (if (bufferp name) name (get-buffer name)))
	 (www (get-buffer-window bbb)))
    (if www
	(progn
	  (select-window www)
	  (set-buffer bbb))	  ; looks but isn't redundant
      (switch-to-buffer bbb))))

		  
(defun buffer-line ()
  (save-excursion
    (buffer-substring (progn (beginning-of-line) (point))
		      (progn (end-of-line) (point)))))