2013-02-26 29 views
9

मैंने एक Emacs Lisp फ़ंक्शन लिखा है जो पर एक शेल कमांड को एक दिए गए स्ट्रिंग को संसाधित करता है और परिणामी स्ट्रिंग को वापस करता है। यहाँ एक सरलीकृत उदाहरण जो सिर्फ tr कॉल अपरकेस करने के लिए पाठ परिवर्तित करने के लिए है:Emacs को पूर्ववत सीमा सेट करने से कैसे रोकें?

(defun test-shell-command (str) 
    "Apply tr to STR to convert lowercase letters to uppercase." 
    (let ((buffer (generate-new-buffer "*temp*"))) 
    (with-current-buffer buffer 
     (insert str) 
     (call-process-region (point-min) (point-max) "tr" t t nil "'a-z'" "'A-Z'") 
     (buffer-string)))) 

इस समारोह, एक अस्थायी बफर बनाता पाठ सम्मिलित करता है, कहता है tr, परिणाम के साथ पाठ की जगह है, और परिणाम देता है।

ऊपर समारोह की उम्मीद रूप में काम करता है, तथापि, जब मैं इस समारोह क्षेत्र के लिए आदेश लागू करने के लिए चारों ओर एक आवरण लिखते हैं, के दो चरण हैं पूर्ववत इतिहास में जोड़ा जा रहा। यहाँ एक और उदाहरण है:

(defun test-shell-command-region (begin end) 
    "Apply tr to region from BEGIN to END." 
    (interactive "*r") 
    (insert (test-shell-command (delete-and-extract-region begin end)))) 

जब मैं फोन M-x test-shell-command-on-region, क्षेत्र अपरकेस पाठ के साथ बदल दिया जाता है, लेकिन जब मैं C-_ (undo) दबाते हैं, तो पूर्ववत इतिहास में पहली कदम का पाठ हटाया वाला राज्य है, । पर जाकर दो कदम पीछे जाएं, मूल पाठ पुनर्स्थापित किया गया है।

मेरा सवाल यह है कि, मध्यवर्ती चरण को से पूर्ववत इतिहास में कैसे जोड़ा जाता है? मैंने Emacs documentation on undo, पढ़ा है, लेकिन जहां तक ​​मैं कह सकता हूं इसे संबोधित नहीं करता है।

यहाँ एक समारोह जो फोन करके एक ही बात सिद्ध है निर्मित Emacs समारोह upcase, बस से पहले के रूप में:

(defun test-upcase-region (begin end) 
    "Apply upcase to region from BEGIN to END." 
    (interactive "*r") 
    (insert (upcase (delete-and-extract-region begin end)))) 

: delete-and-extract-region परिणाम के साथ के परिणाम पर insert को हस्तांतरित कर दिया जा रहा है M-x test-upcase-region पर कॉल करते समय, पूर्ववत इतिहास में केवल एक ही चरण है, जैसा कि अपेक्षित है। तो, ऐसा लगता है कि test-shell-command पर कॉल करना एक पूर्ववत सीमा बनाता है। क्या इसे किसी भी तरह से बचा जा सकता है?

+0

अव्यवस्थित होने से आदेशों को रोकने के लिए हमेशा की तरह '(पूर्ववत करें)' एक अलग तरह से मिल रहा है , वह ऐसा नहीं करता है। यहां उदाहरण यह है कि आपको लगभग अस्थायी बफर कभी नहीं बनाना चाहिए, बल्कि वस्तुओं के साथ काम करना चाहिए। – PascalVKooten

+0

अस्थायी फ़ाइलों को मैन्युअल रूप से पढ़ने और लिखने के अलावा, मुझे प्रक्रिया आउटपुट को कैप्चर करने का एक और तरीका सुनिश्चित नहीं है। यहां तक ​​कि 'स्टार्ट-प्रोसेस' जैसे एसिंक्रोनस प्रोसेस कमांड भी बफर को आउटपुट भेजना चाहते हैं। –

+1

@JasonBlevins 'shell-command-on-region' के लिए पांचवां पैरामीटर प्रतिस्थापन है, तो आपको इसे लपेटने की आवश्यकता क्यों है? –

उत्तर

6

कुंजी बफर नाम है। देखें Maintaining Undo:

नव निर्मित बफर में पूर्ववत जानकारी रिकॉर्डिंग सामान्य रूप से प्रारंभ करने के लिए सक्षम है; लेकिन यदि बफर नाम किसी स्थान के साथ शुरू होता है, तो पूर्ववत रिकॉर्डिंग प्रारंभ में अक्षम होती है। आप निम्न दो फ़ंक्शंस के साथ पूर्ववत रिकॉर्डिंग को सक्षम या अक्षम कर सकते हैं, या बफर-अंडो-सूची स्वयं सेट करके। अपने कार्य *temp* का उपयोग करता है, जबकि

with-temp-buffer, एक बफर ␣*temp* नामित (ध्यान दें अग्रणी खाली स्थान के) पैदा करता है।

अपने कोड में पूर्व सीमा को हटाने के लिए, या तो एक प्रमुख स्थान के साथ बफर नाम का उपयोग करें, या buffer-disable-undo के साथ अस्थायी बफर में पूर्ववत रिकोडिंग अक्षम करें।

लेकिन आम तौर पर, वास्तव में with-temp-buffer का उपयोग करें। Emacs में ऐसी चीजों के लिए यह मानक तरीका है, जो आपके कोड को पढ़ने वाले किसी भी व्यक्ति को अपना इरादा स्पष्ट करता है। इसके अलावा, with-temp-buffer अस्थायी बफर को ठीक से साफ करने के लिए कड़ी मेहनत करता है।


क्यों अस्थायी बफर में पूर्ववत के रूप में वर्तमान में एक पूर्ववत् सीमा बनाता है: यदि पिछले परिवर्तन पूर्ववत करने योग्य था और कुछ अन्य बफर (इस मामले में अस्थायी एक) में किए गए, एक अंतर्निहित सीमा बनाई गई है । undo-boundary से:

सभी बफर संशोधनों एक सीमा जब भी पिछले पूर्ववत करने योग्य परिवर्तन कुछ अन्य बफर में बनाया गया था जोड़ने । यह सुनिश्चित करना है कि प्रत्येक आदेश प्रत्येक बफर में एक सीमा बनाता है जहां यह परिवर्तन करता है।

इसलिए, बाधा अस्थायी बफर में पूर्ववत वर्तमान बफर में पूर्ववत सीमा भी निकालता है: पिछले परिवर्तन बस पूर्ववत करने योग्य अब और नहीं है, और इस प्रकार कोई अंतर्निहित सीमा बनाई गई है।

+1

मैंने सत्यापित किया कि मूल फ़ंक्शन में '(जेनरेट-न्यू-बफर" * temp * ") 'का उपयोग करके और' with-temp-buffer' वास्तव में एक बफर बनाता है जिसका नाम एक प्रमुख स्थान है। मैंने प्रलेखन के उस हिस्से को पढ़ा, लेकिन मुझे नहीं लगता था कि यह मुद्दा था क्योंकि पूर्ववत जानकारी प्रत्येक बफर के लिए विशिष्ट है। मुझे क्यों ध्यान रखना चाहिए कि पूर्ववत जानकारी '* temp *' buffer में दर्ज की गई है या नहीं? लेकिन दस्तावेज से जो मैंने एकत्र नहीं किया वह यह है कि जाहिर है, अन्य बफर में पूर्ववत जानकारी रिकॉर्ड करने का कार्य वर्तमान बफर में पूर्ववत सीमा निर्धारित करना होगा। –

+0

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

2

इस मामले में समाधान, with-temp-buffer का इस्तेमाल करके उनकी स्पष्ट generate-new-buffer के साथ एक बनाने की तुलना में अस्थायी उत्पादन बफर बनाने के लिए किया गया था। पहले समारोह के निम्नलिखित वैकल्पिक संस्करण एक पूर्ववत् सीमा बनाने नहीं करता है:

(defun test-shell-command (str) 
    "Apply tr to STR to convert lowercase letters to uppercase." 
    (with-temp-buffer 
    (insert str) 
    (call-process-region (point-min) (point-max) "tr" t t nil "'a-z'" "'A-Z'") 
    (buffer-string))) 

मैं निर्धारित करने के लिए सक्षम नहीं था कि क्या वास्तव में generate-new-buffer पूर्ववत सीमा बनाने है, लेकिन इस समस्या को तय की। generate-new-bufferget-buffer-create पर कॉल करता है, जिसे सी स्रोत कोड में परिभाषित किया गया है, लेकिन मैं जल्दी से यह निर्धारित नहीं कर सका कि पूर्ववत इतिहास के संदर्भ में क्या हो रहा था।

मुझे लगता है कि इस मुद्दे को Emacs Lisp Manual entry for undo-boundary में निम्नलिखित मार्ग से संबंधित हो सकता:

सभी बफर संशोधनों एक सीमा जब भी पिछले पूर्ववत करने योग्य परिवर्तन कुछ अन्य बफर में बनाया गया था जोड़ें।यह सुनिश्चित करने के लिए है कि प्रत्येक आदेश प्रत्येक बफर में एक सीमा बनाता है जहां यह परिवर्तन करता है।

भी with-temp-buffer मैक्रो कॉल generate-new-buffer मूल कार्य में के रूप में ज्यादा हालांकि, with-temp-buffer के लिए दस्तावेज़ है कि कोई पूर्ववत जानकारी सहेजा जाता है (यहां तक ​​कि हालांकि वहाँ Emacs लिस्प स्रोत में कुछ भी नहीं है कि इस पता चलता है होगा कहा गया है

डिफ़ॉल्ट रूप से, पूर्ववत (पूर्ववत देखें) इस मैक्रो द्वारा बनाई बफर में दर्ज नहीं है (लेकिन शरीर है कि, सक्षम कर सकते हैं यदि आवश्यक हो): मामले) हो।

3

ऐसी कई स्थितियां हैं जहां अस्थायी बफर का उपयोग करना व्यावहारिक नहीं है। उदाहरण के लिए क्या हो रहा है डीबग करना मुश्किल है।

इन मामलों में आप जाने-बाँध undo-inhibit-record-point कर सकते हैं निर्णय लेने से जहां सीमाओं डाल करने के लिए से Emacs को रोकने के लिए:

(let ((undo-inhibit-record-point t)) 
    ;; Then record boundaries manually 
    (undo-boundary) 
    (do-lots-of-stuff) 
    (undo-boundary)) 
संबंधित मुद्दे