मैं एक एमएसीएस मोड पर काम कर रहा हूं जो आपको वाक् पहचान के साथ एमएसीएस को नियंत्रित करने देता है। समस्याओं में से एक मैं भाग गया है कि जिस तरह से Emacs संभालती है वह मेल नहीं खाती है कि आप कैसे आवाज से नियंत्रित करते समय काम करने की उम्मीद करेंगे।
जब उपयोगकर्ता कई शब्द बोलता है और फिर रुक जाता है, तो उसे 'उच्चारण' कहा जाता है। Emacs को निष्पादित करने के लिए एक उच्चारण में कई कमांड शामिल हो सकते हैं। यह अक्सर ऐसा होता है कि पहचानकर्ता गलत तरीके से एक या अधिक आदेशों को पहचानता है। उस बिंदु पर मैं "पूर्ववत" कहने में सक्षम होना चाहता हूं और Emacs को उच्चारण द्वारा किए गए सभी कार्यों को करना है, न कि केवल कथन के भीतर अंतिम क्रिया। दूसरे शब्दों में, मैं चाहता हूं कि Emacs एक आदेश के रूप में एक ही व्यवहार के रूप में जहाँ तक पूर्ववत का संबंध है, तब भी जब एक उच्चारण में कई आदेश होते हैं। मैं यह भी कहना चाहूंगा कि जहां यह उच्चारण करने से पहले था, मैं ठीक उसी ओर जा रहा हूं, मैंने देखा है कि सामान्य Emacs ऐसा नहीं करता है।
मेरे पास प्रत्येक उच्चारण के आरंभ और अंत में कॉलबैक प्राप्त करने के लिए Emacs सेटअप है, इसलिए मैं स्थिति का पता लगा सकता हूं, मुझे केवल यह पता लगाने की आवश्यकता है कि Emacs क्या है। आदर्श रूप से मुझे कुछ पसंद आएगा (undo-start-collapsing)
और फिर (undo-stop-collapsing)
कुछ भी किया जाएगा और इनबेटवाइड जादुई रूप से एक रिकॉर्ड में ढह जाएगा।
मैंने दस्तावेज़ीकरण के माध्यम से कुछ काम किया और पाया undo-boundary
, लेकिन यह इसके विपरीत है जो मैं चाहता हूं - मुझे एक बार में सभी कार्यों को एक पूर्व रिकॉर्ड में ध्वस्त करने की आवश्यकता है, न कि उन्हें विभाजित करना। मैं undo-boundary
यह सुनिश्चित करने के लिए कि आवृत्तियों को अलग माना जाता है, के बीच उपयोग कर सकते हैं (डिफ़ॉल्ट रूप से Emacs लगातार डालने की क्रियाओं को कुछ सीमा तक एक क्रिया मानते हैं), लेकिन यह बात है।
अन्य जटिलताओं:
- मेरा भाषण मान्यता डेमॉन X11 कीपेस का अनुकरण करके Emacs को कुछ कमांड भेजता है और कुछ के माध्यम से भेजता
emacsclient -e
है, अगर वहाँ कहते हैं कि(undo-collapse &rest ACTIONS)
कोई केंद्रीय स्थान नहीं है जो मैं लपेट सकता हूं। - मैं उपयोग करता हूं
undo-tree
, यकीन नहीं तो इससे चीजें और जटिल हो जाएंगी। आदर्श रूप में एक समाधानundo-tree
Emacs के सामान्य पूर्ववत व्यवहार के साथ काम करेगा । - क्या होगा अगर एक उच्चारण के भीतर कोई कमांड "पूर्ववत करें" या "फिर से करें"? मुझे लगता है कि मैं कॉलबैक लॉजिक को हमेशा चीजों को सरल रखने के लिए अलग-अलग कथनों के रूप में Emacs में भेज सकता हूं, फिर इसे वैसे ही संभाला जाए जैसे कि मैं कीबोर्ड का उपयोग कर रहा था।
- खिंचाव लक्ष्य: एक उच्चारण में एक कमांड हो सकती है जो वर्तमान में सक्रिय विंडो या बफर को स्विच करती है। इस मामले में प्रत्येक बफर में एक बार अलग से "पूर्ववत" कहने के लिए ठीक है, मुझे यह कल्पना करने की आवश्यकता नहीं है। लेकिन एक एकल बफ़र में सभी कमांड को अभी भी समूहीकृत किया जाना चाहिए, इसलिए यदि मैं कहता हूं "do-x do-y do-z switch-बफर do-a do-b do-c" तो x, y, z एक पूर्ववत होना चाहिए मूल बफर में रिकॉर्ड और ए, बी, सी को बफर में स्विच करने में एक रिकॉर्ड होना चाहिए।
क्या इसे करने का कोई आसान तरीका है? AFAICT में कुछ भी नहीं बनाया गया है, लेकिन Emacs विशाल और गहरा है ...
अद्यतन: मैंने थोड़ा अतिरिक्त कोड के साथ नीचे jhc के समाधान का उपयोग करके समाप्त किया। वैश्विक में before-change-hook
मैं जाँच करता हूं कि क्या बफर को बदला जा रहा है, बफ़र्स की एक वैश्विक सूची में इस कथन को संशोधित किया गया है, यदि यह सूची में नहीं जाता है और undo-collapse-begin
कहा जाता है। फिर उच्चारण के अंत में मैं सभी बफ़र्स को सूची में बुलाता हूं और कॉल करता हूं undo-collapse-end
। नीचे कोड (नाम-नाम उद्देश्यों के लिए फ़ंक्शन नामों से पहले जोड़ा गया):
(defvar md-utterance-changed-buffers nil)
(defvar-local md-collapse-undo-marker nil)
(defun md-undo-collapse-begin (marker)
"Mark the beginning of a collapsible undo block.
This must be followed with a call to undo-collapse-end with a marker
eq to this one.
Taken from jch's stackoverflow answer here:
http://emacs.stackexchange.com/a/7560/2301
"
(push marker buffer-undo-list))
(defun md-undo-collapse-end (marker)
"Collapse undo history until a matching marker.
Taken from jch's stackoverflow answer here:
http://emacs.stackexchange.com/a/7560/2301"
(cond
((eq (car buffer-undo-list) marker)
(setq buffer-undo-list (cdr buffer-undo-list)))
(t
(let ((l buffer-undo-list))
(while (not (eq (cadr l) marker))
(cond
((null (cdr l))
(error "md-undo-collapse-end with no matching marker"))
((eq (cadr l) nil)
(setf (cdr l) (cddr l)))
(t (setq l (cdr l)))))
;; remove the marker
(setf (cdr l) (cddr l))))))
(defmacro md-with-undo-collapse (&rest body)
"Execute body, then collapse any resulting undo boundaries.
Taken from jch's stackoverflow answer here:
http://emacs.stackexchange.com/a/7560/2301"
(declare (indent 0))
(let ((marker (list 'apply 'identity nil)) ; build a fresh list
(buffer-var (make-symbol "buffer")))
`(let ((,buffer-var (current-buffer)))
(unwind-protect
(progn
(md-undo-collapse-begin ',marker)
,@body)
(with-current-buffer ,buffer-var
(md-undo-collapse-end ',marker))))))
(defun md-check-undo-before-change (beg end)
"When a modification is detected, we push the current buffer
onto a list of buffers modified this utterance."
(unless (or
;; undo itself causes buffer modifications, we
;; don't want to trigger on those
undo-in-progress
;; we only collapse utterances, not general actions
(not md-in-utterance)
;; ignore undo disabled buffers
(eq buffer-undo-list t)
;; ignore read only buffers
buffer-read-only
;; ignore buffers we already marked
(memq (current-buffer) md-utterance-changed-buffers)
;; ignore buffers that have been killed
(not (buffer-name)))
(push (current-buffer) md-utterance-changed-buffers)
(setq md-collapse-undo-marker (list 'apply 'identity nil))
(undo-boundary)
(md-undo-collapse-begin md-collapse-undo-marker)))
(defun md-pre-utterance-undo-setup ()
(setq md-utterance-changed-buffers nil)
(setq md-collapse-undo-marker nil))
(defun md-post-utterance-collapse-undo ()
(unwind-protect
(dolist (i md-utterance-changed-buffers)
;; killed buffers have a name of nil, no point
;; in undoing those
(when (buffer-name i)
(with-current-buffer i
(condition-case nil
(md-undo-collapse-end md-collapse-undo-marker)
(error (message "Couldn't undo in buffer %S" i))))))
(setq md-utterance-changed-buffers nil)
(setq md-collapse-undo-marker nil)))
(defun md-force-collapse-undo ()
"Forces undo history to collapse, we invoke when the user is
trying to do an undo command so the undo itself is not collapsed."
(when (memq (current-buffer) md-utterance-changed-buffers)
(md-undo-collapse-end md-collapse-undo-marker)
(setq md-utterance-changed-buffers (delq (current-buffer) md-utterance-changed-buffers))))
(defun md-resume-collapse-after-undo ()
"After the 'undo' part of the utterance has passed, we still want to
collapse anything that comes after."
(when md-in-utterance
(md-check-undo-before-change nil nil)))
(defun md-enable-utterance-undo ()
(setq md-utterance-changed-buffers nil)
(when (featurep 'undo-tree)
(advice-add #'md-force-collapse-undo :before #'undo-tree-undo)
(advice-add #'md-resume-collapse-after-undo :after #'undo-tree-undo)
(advice-add #'md-force-collapse-undo :before #'undo-tree-redo)
(advice-add #'md-resume-collapse-after-undo :after #'undo-tree-redo))
(advice-add #'md-force-collapse-undo :before #'undo)
(advice-add #'md-resume-collapse-after-undo :after #'undo)
(add-hook 'before-change-functions #'md-check-undo-before-change)
(add-hook 'md-start-utterance-hooks #'md-pre-utterance-undo-setup)
(add-hook 'md-end-utterance-hooks #'md-post-utterance-collapse-undo))
(defun md-disable-utterance-undo ()
;;(md-force-collapse-undo)
(when (featurep 'undo-tree)
(advice-remove #'md-force-collapse-undo :before #'undo-tree-undo)
(advice-remove #'md-resume-collapse-after-undo :after #'undo-tree-undo)
(advice-remove #'md-force-collapse-undo :before #'undo-tree-redo)
(advice-remove #'md-resume-collapse-after-undo :after #'undo-tree-redo))
(advice-remove #'md-force-collapse-undo :before #'undo)
(advice-remove #'md-resume-collapse-after-undo :after #'undo)
(remove-hook 'before-change-functions #'md-check-undo-before-change)
(remove-hook 'md-start-utterance-hooks #'md-pre-utterance-undo-setup)
(remove-hook 'md-end-utterance-hooks #'md-post-utterance-collapse-undo))
(md-enable-utterance-undo)
;; (md-disable-utterance-undo)
buffer-undo-list
मार्कर के रूप में अपनी खुद की प्रविष्टियाँ डालने में सक्षम हो सकते हैं - शायद फॉर्म की प्रविष्टि(apply FUN-NAME . ARGS)
? फिर एक बार फिर से उच्चारण करने के लिएundo
जब तक आप अपना अगला मार्कर नहीं ढूंढ लेते । लेकिन मुझे संदेह है कि यहां सभी तरह की जटिलताएं हैं। :)