« プログラミングを始めるには(33) | Main | プログラミングを始めるには(35) »

September 03, 2014

プログラミングを始めるには(34)

Emacsのプロセス閒通信を使ったプログラムはあまり書いたことがないということで、何か適當なネタはないか、いろいろと考えていたが大した考えは浮かんでこない。それとgnupackをあきらめてCygwinを入れてみたものの、Cygwin端末からマニュアルを參照(man)すると何やらコアダンプしているようで參照出來ない。まあインストールに問題があるのだろうが、それを動くようにあれこれ調べるより、せっかく假想マシンでちゃんと動いているFedoraCentOSUbuntuがあるので、そっちでやった方が良いのではないかと思い始めた。なんか以前もこんなことを書いた氣がする。まあ、便利なUNIXコマンドはelispで書いてみるという樂しみもあるのだが...。

假想マシンとMeadowの閒を行ったり來たりするのはちょっと面倒なので、TeraTermから假想マシン上のFedorasshログインしてみる。これは何も問題なく出來るし、X無しのCygwin代わりになる。TeraTermから起動するEmacsではAltキーが使えないので多少不便だが、むかしはAltよりはESCを多用していたので問題ない。「stty erase ^h」はhelpの參照が不便なので「stty erase ^?」に變更した。

さて、手始めにshellと對話してみよう。

Ws000099


對話の手順としては、「C-x bswitch-to-buffer)」で任意の名前(ここではfoo)のバッファを作り、start-process/bin/bashを起動するだけである。これがEmacsの外にあるプロセスと對話する最も單純な例ではないだろうか。最初にsetenvでプロンプトに空文字列を設定しているのは、fooという名前を付けたプロセスバッファに不要なプロンプトが表示されるからである。バッファから入力を受け付けるわけではないので、プロンプトが表示されると邪魔になるだけだ。起動したbasheofを受け取るまでコマンド入力待ちとして動き續けるので、慌ててprocess-send-stringする必要はない。ただし、コマンド文字列の最後に「\n」を付け忘れると送信したコマンドを實行しない。忘れたら「\n」だけ送ってやるとコマンドを實行する。

(defconst my-start-shell-name "my-start-shell")

(defun my-start-shell ()
  (interactive)
  (or (string= "" (getenv "PS1"))
      (setenv "PS1" ""))
  (let* ((buffer (get-buffer-create my-start-shell-name))
         (proc (start-process my-start-shell-name buffer "/bin/bash")))
    (set-process-filter proc 'my-start-shell-filter)
    (set-process-sentinel proc 'my-start-shell-sentinel)
    (pop-to-buffer buffer)))

(defun my-start-shell-input (command)
  (interactive "s$ ")
  (let* ((proc (get-process my-start-shell-name))
         (buffer (process-buffer proc)))
    (process-send-string proc (concat command "\n"))
    (pop-to-buffer buffer)))

(defun my-start-shell-filter (proc string)
  (with-current-buffer (process-buffer proc)
    (goto-char (marker-position (process-mark proc)))
    (insert-before-markers string "\n")))

(defun my-start-shell-end ()
  (interactive)
  (let* ((proc (get-process my-start-shell-name))
         (buffer (process-buffer proc)))
    (process-send-eof proc)))

(defun my-start-shell-sentinel (proc status)
  (and (string= "exit" status)
       (kill-buffer (process-buffer proc))))

shellとの對話を思いっきり安直に作るとこんな感じだろうか。別にこんなものを作らなくても、shell-commandさえあれば十分と思う人も居るだろう。しかし、非同期プロセスを使用したelispのプログラムを書いたことがない人は一度こういう他愛のないプログラムを書いて試してみると良い。おそらく想像していたのと違った動きをするのが分かるはずだ。私の場合、process-send-eofを實行後にprocess-bufferを消そうとしたら、filterファンクションが呼び出されてバッファに文字列を書き込むことが出來ずエラーとなった。なのでsentinelファンクションを登錄して、プロセスがexitしたらバッファを消そうとしたのだが、結局sentinelファンクションは呼び出されず、バッファは殘ったままとなった。ただ、この動作は私の處理がおかしいからそうなったのか、處理は妥當でもそういう動きになるのかは分からない。いずれにしてもprocess-send-eofした後にfilterファンクションが呼ばれるのは意外だった。

|

« プログラミングを始めるには(33) | Main | プログラミングを始めるには(35) »

Comments

Post a comment



(Not displayed with comment.)


Comments are moderated, and will not appear on this weblog until the author has approved them.



TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/74224/60254499

Listed below are links to weblogs that reference プログラミングを始めるには(34):

« プログラミングを始めるには(33) | Main | プログラミングを始めるには(35) »