re-replace-region: сопоставить данные, затертые перехватчиками модификации буфера

После обновления до версии Aquamacs 3.3 (emacs 25.1.1) я получаю сообщение об ошибке, упомянутое в заголовке, при запуске re-replace-region (как определено ниже), пытаясь изменить строку из 9 в регионе (например, «99» или «999»). ") до 0 с. У меня никогда не было этой проблемы с предыдущими версиями Aquamacs (или emacs в целом), и я не могу придумать ничего ни в среде emacs, ни в машинной среде в целом (Mac OS 10.9.5), что могло бы быть связано с эта проблема.

На самом деле у меня есть исполняемый файл emacs (версия 22.1.1) на той же машине, и после его вызова в той же среде (например, в том же ~/.emacs и т. д.) re-replace-region работает как надо.

Единственная другая подсказка, которую я могу предложить, заключается в том, что при запуске re-replace-region в регионе, скажем, с тремя девятками (999) в нем, пытаясь изменить 9 на 0, первая 9 изменяется до того, как возникнет условие ошибки.

Вот дефун:

;;; RE-REPLACE-REGION replaces OLD (a regular expression) with NEW
;;; throughout the region indicated by BEGIN and END.
;;; For example, to insert a prefix ">" at the beginning of each line
;;; in the region:
;;;   M-x re-replace-regionRET^RET>RET
;;; I don't know who wrote this function!
(defun re-replace-region (begin end old new)
"Replace occurrences of REGEXP with TO-STRING in region."
  (interactive "*r\nsReplace string: \nswith: ")
  (save-excursion
    (save-restriction
      (narrow-to-region begin end)
      (goto-char (point-min))
      (while (re-search-forward old (point-max) t)
        (replace-match new nil nil)))))

person peak    schedule 30.12.2016    source источник
comment
Предоставьте пошаговый рецепт, чтобы воспроизвести проблему, начиная с emacs -Q (нет файла инициализации). Покажите, какие команды и входные данные вы используете и т. д. Если вы или люди здесь можете сказать, что вы не делаете что-то неправильно, рассмотрите возможность сообщения о поведении как об ошибке либо сопровождающим Aquamacs, либо с помощью M-x report-emacs-bug, если вы считаете, что это не связано с Aquamacs. .   -  person Drew    schedule 31.12.2016


Ответы (2)


Я могу сказать вам, что это сообщение об ошибке было представлено в июле 2016 года, что объясняет, почему более старые версии Emacs не вызывали его:

commit 3a9d6296b35e5317c497674d5725eb52699bd3b8
Author: Eli Zaretskii
Date:   Mon Jul 4 18:34:40 2016 +0300

Avoid crashes when buffer modification hooks clobber match data

* src/search.c (Freplace_match): Error out if buffer modification
hooks triggered by buffer changes in replace_range, upcase-region,
and upcase-initials-region clobber the match data needed to be
adjusted for the replacement.  (Bug#23869)

Поэтому я бы сначала предположил, что информация в ошибке верна, и попытаюсь ее подтвердить. Проверьте свои значения для переменных before-change-functions и after-change-functions (в рассматриваемом буфере) и установите, отвечает ли одна из перечисленных функций.

Предположительно, один из них действительно стирает данные совпадения, и тогда это следует рассматривать как ошибку рассматриваемой функции. Если это нестандартно, вам, скорее всего, просто нужно обернуть вызов save-match-data вокруг соответствующего кода.

person phils    schedule 31.12.2016
comment
н.б. @peak предложил обходной путь с использованием replace-regexp, но это далеко не идеально — использование re-search-forward и replace-match является правильным подходом для кода elisp (и строка документации replace-regexp даже указывает на это), так что я не Не рекомендуется использовать этот обходной путь, если вы можете избежать его. - person phils; 01.01.2017
comment
У меня было такое же сообщение об ошибке, но я делал что-то отличное от @peaks. Я установил before-change-functions, after-change-functions, pre-command-hook, post-command-hook пустыми, и все равно были ошибки. На какое-то время я сдался, но только сегодня обнаружил, что не проверил first-change-hook. Это оказалось виновником для меня. - person amitp; 19.04.2017

Проблема возникает из-за того, что переменная before-change-functions равна (aquamacs-undo--rec-region-when-buffer-changes) в затронутых буферах.

Простой обходной путь — использовать replace-regexp вместо re-replace-region. Действительно, это лучше, чем просто обходной путь, потому что при использовании по назначению (т. е. при интерактивном использовании) replace-regexp вызывается следующим образом:

 (replace-regexp REGEX TOSTRING nil
   (if (use-region-p) (region-beginning)) 
   (if (use-region-p) (region-end)) nil)

То есть, если регион определен, replace-regexp влияет только на регион, что, конечно же, в первую очередь является обоснованием для re-replace-region.

Мне все еще было бы интересно узнать больше о (aquamacs-undo--rec-region-when-buffer-changes). Между тем, особенно спасибо @phils.

person peak    schedule 02.01.2017
comment
Похоже, вы должны зарегистрировать отчет об ошибке с сопровождающими aquamacs. - person phils; 03.01.2017
comment
К сожалению, мне не удалось проверить, связана ли проблема с функциями до или после изменения. Действительно, теперь у меня есть буфер, в котором (а) они оба равны нулю; (b) повторная замена области завершается ошибкой, как описано; (c) replace-regexp завершается успешно. Я боюсь, что существование того, что кажется гораздо лучшей альтернативой повторной замене региона, начинает подавлять мое любопытство :-( - person peak; 03.01.2017