[Date Prev] [Date Index] [Date Next]
[Thread Prev] [Thread Index] [Thread Next]

[xyzzy:04132] shell-mode



おおいわです。

xyzzy の shell-mode は、素の DOS よりは遥かに使い勝手いいですが、
例えば pause<RET> と打ってしまうと C-c C-c 以外どうにもならなく
なってしまう (^^; など、emacs と比較するとまだ改良の余地がある
気がします。

# TeX に至っては特定の問い合わせで SIGINT がトラップされているので
# どうにもならなくなってしまいます (^^;
## ESC ESC (process-send-string (buffer-process (selected-buffer)) "x\n") RET
## とか手で入れてその場はしのいだ (^^;;;;;;

というわけで、とりあえず入力判定部分を改善した shell2.l を
作ってみました。

メカニズムとしては、xyzzy に process-mark が存在しない (なぜ?)
ので、process-filter を使って emacsen の process-mark の動作を
エミュレーションします。その上で、process-mark 以降で RET が
押された際には、process-mark と point-max の間の全ての文字列を
送信します。この際には prompt-regexp を使わないのでどんな状況でも
それなりに文字列が送信できます。

TODO: (やるきは未定)
 ・複数行ある時はどうする??

 ・M-p/M-n によるヒストリー検索。
     既存のこの辺りの関数の動作を理解していない (^^;

 ・ファイル名の補完。
     すごくめんどくさそう (^^;
     やるなら cd コマンドを監視してディレクトリを移動することに。

 ・単独のコマンド実行の際もこの動作になって欲しい。
     shell-mode から emacs でいう comint 部分の機能を独立させる?

あと、minibuffer でファイル名や関数名の補完を TAB で行なった際、
2回以上連続で TAB が押された際には *Completion* を1画面スクロール
して欲しいです。面倒でしょうか。>亀井様


;;; -*- Mode: Lisp; Package: LISP -*-
;;;
;;; Original version is part of xyzzy.
;;; modified by Yutaka Oiwa <oiwa@xxxxxxxxxxxxxxxxxx>.
;;;   version 0.1.

(provide "shell")

(in-package "editor")

(export '(*shell-mode-hook* *shell-prompt-regexp* *shell-mode-map*
	  *shell-ret* *shell-echo* shell shell-send-input shell-send-interrupt))

(defvar *shell-mode-hook* nil)
(defvar *shell-prompt-regexp* "^[^#$%>?\n]*[#$%>?] *")
(defvar-local *shell-ret* "\n")
(defvar-local *shell-echo* nil)
(defvar *process-marker* nil)
(make-variable-buffer-local '*process-marker*)

(defvar *shell-mode-map* nil)
(unless *shell-mode-map*
  (setq *shell-mode-map* (make-sparse-keymap))
  (define-key *shell-mode-map* #\RET 'shell-send-input)
  (define-key *shell-mode-map* '(#\C-c #\C-c) 'shell-send-interrupt))

(defun shell-mode ()
  (setq mode-name "Shell")
  (setq buffer-mode 'shell-mode)
  (use-keymap *shell-mode-map*)
  (setq need-not-save t)
  (setq auto-save nil)
  (setq kept-undo-information nil)
  (set-buffer-fold-width 80)
  (cond ((string-matchp *eshell* "command.com$")
	 (setq *shell-ret* "\r" *shell-echo* t))
	((string-matchp *eshell* "cmd.exe$")
	 (setq *shell-ret* "\n" *shell-echo* t))
	(t
	 (setq *shell-ret* "\n" *shell-echo* nil)))
  (run-hooks '*shell-mode-hook*))

(defun shell ()
  (interactive)
  (set-buffer (get-buffer-create "*Shell*"))
  (let ((proc (buffer-process (selected-buffer))))
    (and proc (eq (process-status proc) ':run)
	 (return-from shell t)))
  (goto-char (point-max))
  (shell-mode)
  (let ((proc (make-process *eshell* :output (selected-buffer))))
    (set-process-filter proc #'shell-process-filter)
  )
  (setq *process-marker* (make-marker))
  (set-marker *process-marker* (point-max))
)

(defun shell-process-filter (proc str)
  (let ((*inhibit-quit* t) ;; for xyzzy prior to 0.2.0.124.
	(old-buffer (selected-buffer))
	(old-window (selected-window))
	(win-config (current-window-configuration))
	(buf (process-buffer proc))
	pt
       )
    (unwind-protect
	(progn
	  (set-buffer buf)
	  (let ((e (and (markerp *process-marker*) (= (marker-point *process-marker*) (point-max)))))
            (save-excursion
	     (if (markerp *process-marker*)
		 (goto-marker *process-marker*)
	       (goto-char (point-max)))
	     (insert str)
	     (setq pt (point))
	    )
	    (set-marker *process-marker* pt)
	    (when e
	      (set-window (get-buffer-window buf))
;	      (message (format nil "~A ~A ~A" (marker-point *process-marker*) (point) (point-max)))
	      (goto-char (point-max))
	    )
	  ))
      (set-window old-window)
      (set-buffer old-buffer)
      (refresh-screen)))
;  (message str)
)

(defun shell-send-input ()
  (interactive)
  (if (markerp *process-marker*)
      (let ((start (marker-point *process-marker*))
	    (end (point-max)))
	(if (<= start (point))
	    (let ((str (buffer-substring start end)))
	      (setq str (string-right-trim '(#\LFD #\RET) str))
	      (delete-region start end)
	      (unless *shell-echo*
		(insert str "\n"))
	      (process-send-string (buffer-process (selected-buffer))
				   (concat str *shell-ret*))
	      (return-from shell-send-input t)))))
  ; original shell-send-input starts
  (when (save-excursion
	  (goto-bol)
	  (looking-at *shell-prompt-regexp*))
    (let* ((tail (progn (goto-eol) (point)))
	   (cmd (buffer-substring (match-end 0) tail)))
      (cond ((eobp)
	     (if *shell-echo*
		 (delete-region (match-end 0) tail)
	       (insert "\n")))
	    (t
	     (goto-char (point-max))
;	     (or (bolp)
;		 (insert "\n"))
;	     (insert (match-string 0))
	     (unless *shell-echo*
	       (insert cmd "\n"))))
      (process-send-string (buffer-process (selected-buffer))
			   (concatenate 'string cmd *shell-ret*)))))

(setf (symbol-function 'shell-send-interrupt) #'kill-subprocess)


-- 
大岩 寛   Yutaka Oiwa
       東京大学大学院 理学系研究科情報科学専攻 修士課程 米澤研究室
      <oiwa@xxxxxxxxxxxxxxxxxxxxx>, <yutaka@xxxxxxxxxxxxxxxxxxxxx>
PGP fingerprint = C9 8D 5C B8 86 ED D8 07  EA 59 34 D8 F4 65 53 61

Index Home