अतुल्यकालिक रूप से एक comint प्रक्रिया से आउटपुट की प्रतीक्षा करें


12

सबसे पहले, एक अस्वीकरण। मैंने कई बार इस पर शोध किया है, और मुझे पूरा यकीन है कि मुझे पहले से ही एक या दूसरे तरीके का जवाब मिल गया है, लेकिन मैं अभी इसे समझ नहीं पाया हूं।

मेरी समस्या निम्नलिखित है:

  • मेरे पास कॉमिंट के माध्यम से एक प्रक्रिया चल रही है
  • मैं इनपुट की एक लाइन भेजना चाहता हूं, आउटपुट कैप्चर करना चाहता हूं और देखना चाहता हूं कि कब खत्म हो (जब आउटपुट की आखिरी लाइन एक प्रॉम्प्ट के लिए regexp से मेल खाती है)
  • केवल जब प्रक्रिया ने आउटपुट भेजना समाप्त कर दिया है, मैं इनपुट की दूसरी पंक्ति (उदाहरण के लिए) भेजना चाहता हूं।

पृष्ठभूमि के एक बिट के लिए, एक कार्यक्रम के साथ बातचीत को लागू करने वाले एक प्रमुख मोड के बारे में सोचें, जो लंबे समय तक मध्यस्थता में, आउटपुट की एक मनमानी राशि वापस कर सकता है। यह एक असामान्य स्थिति नहीं होनी चाहिए, है ना? ठीक है, शायद वह हिस्सा जहां मुझे इनपुट के बीच इंतजार करना असामान्य है, लेकिन इनपुट को समग्र रूप से भेजने के कुछ फायदे हैं:

  • आउटपुट बफर अच्छी तरह से स्वरूपित है: इनपुट आउटपुट इनपुट आउटपुट ...
  • इससे भी महत्वपूर्ण बात यह है कि एक प्रक्रिया में बहुत सारे पाठ भेजते समय, पाठ को टुकड़ों में काट दिया जाता है और टुकड़ों को प्रक्रिया द्वारा वापस चिपका दिया जाता है; काटने के बिंदु मनमाने हैं और यह कभी-कभी अमान्य इनपुट बनाता है (मेरी प्रक्रिया सही ढंग से वापस नहीं आएगी, उदाहरण के लिए एक पहचानकर्ता के बीच में एक इनपुट कटौती)

वैसे भी, असामान्य है या नहीं, यह पता चला है कि यह है जटिल। अभी, मैं की तर्ज पर कुछ का उपयोग कर रहा हूँ

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

और मैं हर बार इनपुट लाइन भेजने के बाद, और अगले को भेजने से पहले इसे कॉल करता हूं। अच्छा ... यह काम करता है, यह पहले से ही कुछ है।

लेकिन यह आउटपुट के इंतजार के दौरान एमएसीएस को लटका भी देता है। कारण स्पष्ट है, और मुझे लगा कि अगर मैंने sleep-forलूप में किसी तरह के एसिंक्रोनस (उदाहरण के लिए 1s) को शामिल किया है तो यह 1 एस से आउटपुट में देरी करेगा, लेकिन फांसी को दबा देगा। सिवाय इसके कि ऐसा लगता है कि इस तरह की अतुल्यकालिक sleep-for मौजूद नहीं है

या करता है? अधिक आम तौर पर, वहाँ इस emacs के साथ प्राप्त करने का एक मुहावरेदार तरीका है? दूसरे शब्दों में:

किसी प्रक्रिया में इनपुट कैसे भेजें, आउटपुट की प्रतीक्षा करें, फिर अतुल्यकालिक रूप से अधिक इनपुट भेजें?

जब चारों ओर खोज (संबंधित प्रश्नों को देखें), मैंने मुख्य रूप से प्रहरी का उल्लेख देखा है (लेकिन मुझे नहीं लगता कि यह मेरे मामले में लागू होता है, क्योंकि प्रक्रिया समाप्त नहीं होती है) और कुछ कॉमिंट हुक के (लेकिन फिर क्या चाहिए?) हुक को बफ़र-स्थानीय बनाएं, मेरी "शेष रेखाओं का मूल्यांकन" एक फंक्शन में करें, इस फंक्शन को हुक में जोड़ें और हुक को बाद में साफ़ करें; यह वास्तव में गंदा लगता है, है ना?)।

मुझे खेद है कि अगर मैं खुद को स्पष्ट नहीं कर रहा हूं, या अगर कहीं एक स्पष्ट जवाब उपलब्ध है, तो मैं वास्तव में प्रक्रिया की बातचीत की सभी जटिलताओं से भ्रमित हूं।

यदि आवश्यक हो, तो मैं यह सब एक कार्यशील उदाहरण बना सकता हूं, लेकिन मुझे डर है कि यह सिर्फ एक और "विशिष्ट प्रक्रिया उत्तर के साथ विशिष्ट प्रक्रिया प्रश्न" बना देगा, जो मुझे पहले मिला था और मेरी मदद नहीं की।

SO पर कुछ संबंधित प्रश्न:


@nicael संबंधित लिंक के बारे में क्या गलत है?
टी। वेरॉन

लेकिन आपको उन्हें शामिल करने की आवश्यकता क्यों है?
nicael

2
ठीक है, मैंने उन्हें संबंधित प्रश्न किए हैं, भले ही उत्तरों ने मेरी मदद नहीं की हो। अगर कोई मेरी मदद करना चाहता है, तो संभवत: उन्हें इस मामले की गहरी जानकारी होगी जो मेरे पास है, लेकिन हो सकता है कि उन्हें अब भी पहले से ही एक शोध करने की आवश्यकता हो। इस मामले में, सवाल उन्हें कुछ शुरुआती बिंदु देते हैं। और इसके अलावा, अगर किसी दिन इस पृष्ठ पर भूमि होती है, लेकिन एक समस्या के साथ जो मैं जुड़ा हुआ हूं, वे एक जैसे हैं, तो उनके पास उचित प्रश्न का शॉर्टकट होगा।
टी। वेरॉन

@nicael (पहली पोस्ट में पिंग करना भूल गया, क्षमा करें) क्या यह समस्या है कि लिंक mx.sx से नहीं हैं?
टी। वेरॉन

ठीक। आप अपने संशोधन, इसकी पोस्ट पर वापस जा सकते हैं।
nicael

जवाबों:


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-preoutput-filter-functions, उन्हें एक तर्क के रूप में नया पाठ पास करें।
  • के आधार पर कुछ तदर्थ डुप्लिकेट शीघ्र उन्मूलन प्रदर्शन करें comint-prompt-regexp
  • बफर के अंत में प्रक्रिया आउटपुट डालें
  • सूची में फ़ंक्शन चलाएं comint-output-filter-functions, उन्हें एक तर्क के रूप में नया पाठ पास करें।

यह देखते हुए कि आपका मोड कॉमिंट पर आधारित है, आपको अपना फ़िल्टर रजिस्टर करना चाहिए comint-output-filter-functions। आपको comint-prompt-regexpअपने प्रॉम्प्ट से मिलान करना चाहिए । मुझे नहीं लगता कि कॉमिंट के पास एक पूर्ण आउटपुट चंक (यानी दो संकेतों के बीच) का पता लगाने के लिए एक अंतर्निहित सुविधा है, लेकिन यह मदद कर सकता है। मार्कर 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 को comac.el में Emacs 25 में परिभाषित नहीं किया गया लगता है। क्या यह कहीं और से है?
जॉन किचिन

@JohnKitchin का यह भाग 24.4 में बदल गया, मैंने अपना उत्तर 24.3 में लिखा। मैंने एक पोस्ट -24.4 विधि जोड़ी है।
गाइल्स का SO- बुराई होना बंद हो '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.