comintプロセスからの出力を非同期に待機します


12

まず、免責事項。私はこれを何度も研究しました、そして、私はすでに何らかの方法で答えをすでに見つけたと確信していますが、私はそれを理解しません。

私の問題は次のとおりです。

  • comintを実行しているプロセスがあります
  • 入力行を送信し、出力をキャプチャして、それが終了したとき(出力の最後の行がプロンプトの正規表現に一致したとき)を確認したい
  • プロセスが出力の送信を完了したときにのみ、別の入力行を送信したい(たとえば)。

少しの背景として、プログラムとの対話を実装するメジャーモードを考えてください。プログラムは、任意の時間で任意の量の出力を返す可能性があります。これは異常な状況ではありませんよね?さて、 入力間で待機する必要がある部分は珍しいかもしれませんが、入力全体を送信するよりもいくつかの利点があります。

  • 出力バッファはきれいにフォーマットされています:入力出力入力出力...
  • さらに重要なことは、プロセスに大量のテキストを送信する場合、テキストは断片に分割され、その断片はプロセスによって貼り付けられます。切断ポイントは任意であり、これにより無効な入力が行われることがあります(たとえば、プロセスは識別子の途中で入力カットを正しく貼り付けません)

とにかく、珍しいかどうかにかかわらず、それ複雑であることわかります。今、私はの線に沿って何かを使用しています

(defun mymode--wait-for-output ()
  (let ((buffer (mymode-get-buffer)))
    (with-current-buffer buffer
      (goto-char (point-max))
      (forward-line 0)
      (while (not (mymode-looking-at-prompt))
        (accept-process-output nil 0.001)
        (redisplay)
        (goto-char (point-max))
        (forward-line 0))
      (end-of-line))))

入力ラインを送信した後、次のラインを送信する前に毎回これを呼び出します。まあ...それは動作します、それはすでに何かです。

ただし、出力を待機しているときにemacsがハングすることもあります。その理由は明らかでありsleep-for、ループに何らかの非同期(たとえば1)を含めると、出力は1秒遅延しますが、ハングは抑制されると考えました。この種の非同期sleep-for は存在しないように見えることを除いて 。

それともそうですか?より一般的には、emacsでこれを達成する慣用的な方法はありますか?言い換えると:

プロセスに入力を送信し、出力を待ってから、さらに入力を非同期に送信する方法は?

周りを検索するとき(関連する質問を参照)、主にセンチネル(プロセスが終了しないため、私の場合には当てはまらないと思います)といくつかのcomintフック(しかし、何をすべきですか?フックをバッファローカルにし、「残りの行を評価する」を関数に変え、この関数をフックに追加し、その後フックをきれいにしますか?それは本当に汚いですね?)

自分自身を明確にしない場合、またはどこかで利用可能な明らかな答えがある場合、プロセスの相互作用のすべての複雑さに本当に混乱しています。

必要に応じて、これをすべて実用的な例にすることができますが、以前に見つけて助けにならなかったすべてのような「特定のプロセスの答えを持つ特定のプロセスの質問」をもう1つ作成するだけです。

SOに関するいくつかの関連する質問:


@nicael関連リンクの何が問題になっていますか?
T.バーロン14年

しかし、なぜそれらを含める必要があるのですか?
ニカエル14年

1
答えが役に立たなかったとしても、それらは関連する質問であることがわかりました。誰かが私を助けたいと思うなら、おそらく彼らは私よりも深い知識を持っているでしょうが、彼らはまだ事前に研究を行う必要があるでしょう。この場合、質問によって出発点が与えられます。さらに、いつか誰かがこのページにアクセスしたが、私がリンクしたものと同じような問題がある場合、適切な質問へのショートカットがあります。
T.バーロン14年

@nicael(最初の投稿でpingを忘れてしまった、すみません)リンクがmx.sxからのものではないのは問題ですか?
T.バーロン14年

OK。リビジョン、その投稿にロールバックできます。
ニカエル14年

回答:


19

まず、accept-process-output非同期処理が必要な場合は使用しないでください。Emacsは、ユーザーの入力を待機するたびに出力を受け入れます。

適切な方法は、フィルター関数を使用して出力をインターセプトすることです。送信する行があるかどうかに応じて、フィルターを作成または削除する必要はありません。むしろ、通常、プロセスの存続期間に対して単一のフィルターを宣言し、バッファーローカル変数を使用して状態を追跡し、必要に応じてさまざまなことを行います。

低レベルのインターフェース

フィルタ関数はあなたが探しているものです。フィルター機能は、終了するセンチネルを出力します。

(defun mymode--output-filter (process string)
  (let ((buffer (process-buffer process)))
    (when (buffer-live-p buffer)
      (with-current-buffer buffer
        (goto-char (point-max))
        (forward-line 0)
        (when (mymode-looking-at-prompt)
          (do-something)
          (goto-char (point-max)))))))

手動で、または(Emacsに付属して多くの例を見てgrepのためprocess-filter.elファイル)。

フィルター関数を登録します

(set-process-filter 'mymode--output-filter)

comintインターフェース

Comintは、いくつかのことを行うフィルター関数を定義しています。

  • プロセス出力を含む必要があるバッファに切り替えます。
  • リスト内の関数を実行comint-preoutput-filter-functionsし、引数として新しいテキストを渡します。
  • に基づいて、アドホックな重複プロンプトの除去を実行しcomint-prompt-regexpます。
  • バッファの最後にプロセス出力を挿入します
  • リスト内の関数を実行comint-output-filter-functionsし、引数として新しいテキストを渡します。

モードがcomintに基づいている場合、フィルターをに登録する必要がありますcomint-output-filter-functionscomint-prompt-regexpプロンプトに合わせて設定する必要があります。Comintには完全な出力チャンク(2つのプロンプト間)を検出するための組み込み機能はないと思いますが、それは役立ちます。マーカーcomint-last-input-endは、最後の入力チャンクの最後に設定されます。最後のプロンプトの終わりがの後にある場合、新しい出力チャンクがありますcomint-last-input-end。最後のプロンプトの終わりを見つける方法は、Emacsのバージョンによって異なります。

  • 最大24.3まで、オーバーレイcomint-last-prompt-overlayは最後のプロンプトにまたがります。
  • 24.4以降、変数comint-last-promptには最後のプロンプトの開始と終了のマーカーが含まれています。
(defun mymode--comint-output-filter (string)
  (let ((start (marker-position comint-last-input-end))
        (end (if (boundp 'comint-last-prompt-overlay)
                 (and comint-last-prompt-overlay (overlay-start comint-last-prompt-overlay))
               (and comint-last-prompt (cdr comint-last-prompt))))
  (when (and start end (< start end))
    (let ((new-output-chunk (buffer-substring-no-properties start end)))
      ...)))

プロセスが{入力を受け取る、出力を出す、プロンプトを表示する}以外の順序で出力を出す場合に保護を追加することができます。


変数comint-last-prompt-overlayは、comint.elのEmacs 25では定義されていないようです。それはどこか他の人からですか?
ジョンキッチン

@JohnKitchin comintのその部分は24.4で変更されたので、24.3の答えを書きました。post-24.4メソッドを追加しました。
ジル 'SO-悪であるのをやめる'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.