Eş zamanlı olmayan bir işlemden çıkış beklemek


12

Her şeyden önce, bir feragatname. Bunu birçok kez araştırdım ve cevabı zaten bir şekilde bulduğuma eminim, ama sadece anlamıyorum.

Benim sorunum şudur:

  • Comint üzerinden geçen bir süreç var
  • Bir girdi satırı göndermek, çıktıyı yakalamak ve ne zaman bittiğini görmek istiyorum (çıktının son satırı bir istem için normal ifadeyle eşleştiğinde)
  • yalnızca işlem çıktı göndermeyi bitirdiğinde, başka bir girdi satırı göndermek istiyorum (örneğin).

Biraz arka plan için, keyfi olarak uzun bir süre içinde keyfi bir çıktı verebilecek bir programla etkileşim uygulayan büyük bir modu düşünün. Bu alışılmadık bir durum olmamalı, değil mi? Tamam, belki de girişler arasında beklemem gereken kısım olağandışıdır, ancak girişi bir bütün olarak göndermeye göre birkaç avantajı vardır:

  • çıkış tamponu güzel biçimlendirilmiş: giriş çıkış giriş çıkış ...
  • daha da önemlisi, bir sürece çok fazla metin gönderirken, metin parçalara ayrılır ve parçalar süreç tarafından yapıştırılır; kesme noktaları isteğe bağlıdır ve bu bazen geçersiz girdi yapar (örneğin, işlemim bir tanımlayıcının ortasındaki bir girdi kesimini doğru şekilde yapıştırmaz)

Neyse, olağandışı ya da olmasın, o çıkıyor edilir karmaşık. Şu anda, bir şey kullanıyorum

(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))))

ve bunu her giriş hattı gönderdikten sonra ve bir sonrakini göndermeden önce çağırıyorum. Şey ... işe yarıyor, bu zaten bir şey.

Ama aynı zamanda çıkış beklerken emacs asmak yapar. Nedeni açıktır ve sleep-fordöngüye bir tür asenkron (örneğin 1s) eklersem çıktıyı 1s geciktirir, ancak asılıyı bastırır. Dışında bu tür bir asenkron var sleep-for gibi görünmüyor .

Yoksa öyle mi? Daha genel olarak, bunu emacs ile başarmanın deyimsel bir yolu var mı? Diğer bir deyişle:

Bir işleme girdi göndermek, çıktıyı beklemek, sonra eşzamansız olarak daha fazla girdi göndermek nasıl?

Etrafta arama yaparken (ilgili sorulara bakın), esas olarak nöbetçilerden bahsederim (ancak işlem bitmediği için benim durumumda geçerli olduğunu düşünmüyorum) ve bazı comint kancalardan (ama sonra ne? kanca tampon-yerel yapmak, benim "kalan satırları değerlendirmek" bir fonksiyona çevirmek, bu işlevi kanca eklemek ve daha sonra kanca temizlemek? gerçekten kulağa geliyor, değil mi?).

Kendimi açıklığa kavuşturmamaya üzüldüğüm için üzgünüm ya da bir yerde gerçekten açık bir cevap varsa, süreç etkileşiminin tüm karmaşıklıklarıyla gerçekten kafam karıştı.

Gerekirse, tüm bunları çalışan bir örnek haline getirebilirim, ancak daha önce bulduğum ve bana yardım etmeyenler gibi bir "spesifik süreç cevabına sahip özel süreç sorusu" daha yapacağından korkuyorum.

SO ile ilgili bazı sorular:


@nicael İlgili bağlantıların sorunu nedir?
T. Verron

Ama neden onları dahil etmeniz gerekiyor?
nicael

2
Yanıtlar bana yardımcı olmasa bile, onları ilgili sorular olarak buldum. Birisi bana yardım etmek istiyorsa, muhtemelen benden daha derin bir bilgiye sahip olacaklar, ancak belki de önceden bir araştırma yapmaları gerekecek. Bu durumda, sorular onlara bir başlangıç ​​noktası verir. Ayrıca, bir gün birisi bu sayfaya gelirse, ancak bağlantı kurduğum kişilerle aynı sorunla karşılaşırsa, uygun soru için bir kısayol olacaktır.
T. Verron

@nicael (İlk yazıda ping atmayı unuttum, özür dilerim) Bağlantıların mx.sx'ten olmaması bir sorun mu var?
T. Verron

Tamam. Revizyonunuza geri dönebilirsiniz, bu sizin yazınız.
nicael

Yanıtlar:


19

Her şeyden önce, zaman accept-process-outputuyumsuz işleme istiyorsanız kullanmamalısınız . Emacs, kullanıcı girişini her beklediğinde çıkışı kabul eder.

Gitmenin uygun yolu, çıktıyı kesmek için filtre işlevlerini kullanmaktır. Hala gönderilecek satırınız olup olmadığına bağlı olarak filtreleri oluşturmanız veya silmeniz gerekmez. Bunun yerine, genellikle işlemin ömrü boyunca tek bir filtre bildirir ve durumu izlemek ve gerektiğinde farklı şeyler yapmak için arabellek-yerel değişkenleri kullanırsınız.

Düşük seviye arayüz

Filtre işlevleri aradığınız şeydir. Filtre fonksiyonları, sentinellerin sonlandırılacağı çıktıyı vermektir.

(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)))))))

Manuel ya da (Emacs ile gelen birçok örneklere bakın grepiçin process-filterde .eldosyalar).

Filtre işlevinizi ile kaydedin

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

Comint arayüzü

Comint, birkaç şey yapan bir filtre işlevi tanımlar:

  • İşlem çıktısını içermesi gereken arabelleğe geçin.
  • Listedeki işlevleri çalıştırın ve comint-preoutput-filter-functionsyeni metni bağımsız değişken olarak iletin.
  • Dayalı bazı geçici yinelenen istemi ortadan kaldırın comint-prompt-regexp.
  • İşlem çıktısını tamponun sonuna ekleyin
  • Listedeki işlevleri çalıştırın ve comint-output-filter-functionsyeni metni bağımsız değişken olarak iletin.

Modunuzun comint'e dayandığı göz önüne alındığında, filtrenizi kaydettirmelisiniz comint-output-filter-functions. İsteminize comint-prompt-regexpuyacak şekilde ayarlamanız gerekir . Ben Comint tam bir çıktı yığın tespit etmek için yerleşik bir tesis olduğunu sanmıyorum (yani iki istem arasında), ama yardımcı olabilir. İşaretleyici comint-last-input-end, son giriş yığınının sonunda ayarlanır. Son istemin sonu geldiğinde yeni bir çıktı yığınınız var comint-last-input-end. Son istemin sonunu bulma Emacs'ın sürümüne bağlıdır:

  • 24.3'e kadar yer paylaşımı comint-last-prompt-overlayson istemi kapsar.
  • 24.4'ten beri, değişken comint-last-promptson istemin başlangıcında ve sonunda işaretçiler içerir.
(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)))
      ...)))

Sürecin çıktıyı {alma girişi, çıktı çıkışı, görüntü istemi} dışında bir sırada yayınlaması durumunda koruma eklemek isteyebilirsiniz.


Comint-last-istem-yer paylaşımı değişkeni comint.el'deki Emacs 25'te tanımlanmış gibi görünmüyor. Başka bir yerden mi geliyor?
John Kitchin

@JohnKitchin Comint'in bu kısmı 24.4'te değişti, cevabımı 24.3 için yazmıştım. 24.4 sonrası bir yöntem ekledim.
Gilles 'SO- kötü olmayı bırak'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.