файл заполнения абзаца помечается как измененный, даже если он ничего не делал

11

Всякий раз, когда я вызываю fill-paragraph, буфер всегда помечается как измененный, даже если команда не имела никакого эффекта (то есть, если абзац уже был заполнен). Он также создает пустое отменяемое действие (легко обнаруживается с помощью undo-tree-mode). Другие команды, которые могут вносить изменения, такие как команды отступа, не помечают буфер как измененный или создают отменяемое действие, если ничего не было изменено. Есть ли способ fill-paragraphпометить измененный буфер и создать отменяемое действие, только если оно действительно что-то изменило?

Лили Чунг
источник
Я не думаю, что это правильно M-q- не помечает буфер, измененный по умолчанию, по крайней мере, из моего тестирования. Какой режим вы используете? Я предполагаю, что режим перезаписывается fill-paragraphкаким-то образом.
Шости
@shosti Я использую основной режим. Абзац должен быть длиной более одной строки (при правильном заполнении).
Лили Чунг,
Ах, хорошо, я вижу это сейчас.
Шости

Ответы:

2

Обратите внимание, что это исправлено для более новой версии Emacsen (v.26 и выше).

clemera
источник
10

Проблема в том, что fill-paragraph(или, скорее, fill-region-as-paragraph) удалит и повторно вставит новые строки, пока он разбивает ваш абзац. Он не изменит буфер, если будет только одна строка. Нет в списке отмены, свидетелем которого вы являетесь, - это просто fill-paragraphудаление и повторная вставка новых строк.

Это не тривиально, чтобы избежать этого. Следующее является довольно плохим хаком и крайне неэффективно для больших буферов, но, возможно, оно работает для вас. Команда mimics fill-paragraph( M-q) действует идентично, за исключением того, что она сохраняет содержимое буфера до его вызова, а затем, если содержимое остается прежним, восстанавливает состояние изменения и список отмены до изменения. Для этого ему нужна копия (фактически две) содержимого буфера, так что на самом деле это довольно неэффективно. :-)

(defun my/fill-paragraph (&optional justify region)
  (interactive (progn
                 (barf-if-buffer-read-only)
                 (list (if current-prefix-arg 'full) t)))
  (let ((old-text (buffer-string))
        (old-modified (buffer-modified-p))
        (old-undo-list buffer-undo-list))
    (fill-paragraph justify region)
    (when (equal old-text (buffer-string))
      (setq buffer-undo-list old-undo-list)
      (set-buffer-modified-p old-modified))))

Вы можете связать это с M-q.

Йорген Шефер
источник
1
Да, это долго было болью. ;-) Интересно (я не помню), было ли запрошено исправление для этого раньше. Похоже, это было бы.
Дрю
Хммм. Интересно, есть ли лучшее решение, которое не должно проверять весь буфер - может быть, оно каким-то образом может проверять только выбранный абзац?
Лили Чунг
fill-paragraphделает некоторые различия между различными случаями, то есть ведет себя по-разному в зависимости от активной области, существующих функций заполнения абзаца и т. д. Вам придется повторить это поведение, чтобы выяснить, какие части буфера действительно будут изменены. Возможно, но сложно. :-)
Йорген Шефер
@Drew В прошлом году об этом долго говорили в списке рассылки: ошибка # 13949: 24.3.50; «Заполнить абзац» не всегда должен помещать буфер как измененный
dkim
@dkim: Да, я помню сейчас. И ничего из этого не вышло ...
Дрю
1

Поздний ответ, но вот простая версия, которая не изменяет буфер, если текст не изменяется.

(defun my-fill-paragraph (&optional justify region)
  "Fill paragraph, but don't modify the buffer if filling doesn't
change the text.  See `fill-paragraph' for details."
  (interactive (progn
                 (barf-if-buffer-read-only)
                 (list (if current-prefix-arg 'full) t)))
  (if (buffer-modified-p)
      ;; if modified: use standard fill-paragraph
      (fill-paragraph justify region)
    ;; if unmodified: get a candidate filled version
    (save-excursion
      (let* ((col fill-column)
             (beg (progn (forward-paragraph -1)
                         (skip-syntax-forward " >")
                         (point)))
             (end (progn (forward-paragraph 1)
                         (skip-syntax-backward " >")
                         (point)))
             (old (buffer-substring-no-properties beg end))
             (new (with-temp-buffer
                    (setq fill-column col)
                    (insert old)
                    (fill-paragraph justify region)
                    (buffer-string))))
        ;; don't modify unless the old and new versions differ
        (unless (string-equal old new)
          (delete-region beg end)
          (insert new))))))

Он адаптирует некоторые идеи из ответа @ JorgenSchäfer, но работает только с текущим абзацем и только простым, разделенным пробелами способом (см. Комментарии @ JorgenSchäfer об осложнениях под капотом).

Это касается единственного варианта использования, который подходит для моих собственных целей (то есть интерактивного использования с «нормальной» прозой, без активной области), поэтому я публикую его на тот случай, если кто-то захочет использовать его или улучшить для более сложных вариантов использования. ,

Дэн
источник