Emacs save-place-place-alist в файл при уничтожении буфера: почему у меня возникают проблемы глубины рекурсии с ловушкой? - PullRequest
0 голосов
/ 28 апреля 2020

Я использую Emacs (на данный момент 26.3) довольно давно (годы). У меня всегда было

(use-package saveplace
  :config
  (save-place-mode t))

в моем init.el, что заставляет Emacs использовать save-place-mode (который поставляется с ванильным Emacs как saveplace.el) для запоминания последней позиции в файле.

Моя проблема с saveplace заключается в том, что он сохраняет сохраненные файлы и позиции в список с именем save-place-alist и только через хук в kill-emacs-hook сбрасывает этот список в местоположение по умолчанию ~/.emacs.d/places. Но это случается довольно часто, что я забываю или как-то обычно не покидаю свой emacs-демон. Итак, список будет потерян.

Мой подход заключался в том, чтобы извлечь функцию save-place-alist-to-file из saveplace.el и добавить ее в kill-buffer-hook, поэтому теперь каждый раз, когда я уничтожаю буфер, save-place-alist будет сохранено на диск. Вот как выглядит моя конфигурация для сохранения:

(defun my-save-place-alist-to-file ()
(interactive)
(save-place-to-alist)
  (let ((file (expand-file-name save-place-file))
        (coding-system-for-write 'utf-8))
    (with-current-buffer (get-buffer-create " *Saved Places*")
      (delete-region (point-min) (point-max))
      (when save-place-forget-unreadable-files
        (save-place-forget-unreadable-files))
      (insert (format ";;; -*- coding: %s -*-\n"
                      (symbol-name coding-system-for-write)))
      (let ((print-length nil)
            (print-level nil))
        (pp save-place-alist (current-buffer)))
      (let ((version-control
             (cond
              ((null save-place-version-control) nil)
              ((eq 'never save-place-version-control) 'never)
              ((eq 'nospecial save-place-version-control) version-control)
              (t
               t))))
        (condition-case nil
            ;; Don't use write-file; we don't want this buffer to visit it.
            (write-region (point-min) (point-max) file)
          (file-error (message "Saving places: can't write %s" file)))
        (kill-buffer (current-buffer))))))

(use-package saveplace
  :config
  (save-place-mode t)
  ;; (remove-hook 'kill-buffer-hook 'save-place-to-alist)
  ;; (add-hook 'kill-buffer-hook 'my-save-place-alist-to-file))

Все в порядке, пока я не изменяю kill-buffer-hook, раскомментируя последние строки. Функция my-save-place-alist-to-file работает правильно при интерактивном вызове. Но когда активируешь крючки, буквально все тормозит. Прежде всего я больше не могу убивать буферы. Я получаю эту ошибку, связанную с глубиной рекурсии:

progn: Variable binding depth exceeds max-specpdl-size

Отладчик говорит:

Debugger entered--Lisp error: (error "Variable binding depth exceeds max-specpdl-size")
  generate-new-buffer(" *temp*")
  pp-to-string((("/home/.../test.txt" . 33)))
  pp((("/home/.../test.txt" . 33)) #<buffer  *Saved Places*>)
  (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer)))
  (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq (quote never) save-place-version-control) (quote never)) ((eq (quote nospecial) save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer))))
  (let ((file (expand-file-name save-place-file)) (coding-system-for-write (quote utf-8))) (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq ... save-place-version-control) (quote never)) ((eq ... save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer)))))
  my-save-place-alist-to-file()
  kill-buffer(#<buffer  *temp*-840370>)
  #f(compiled-function () #<bytecode 0x1c65c75>)()
  pp-to-string((("/home/.../test.txt" . 33)))
  pp((("/home/.../test.txt" . 33)) #<buffer  *Saved Places*>)
  (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer)))
  (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq (quote never) save-place-version-control) (quote never)) ((eq (quote nospecial) save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer))))
  (let ((file (expand-file-name save-place-file)) (coding-system-for-write (quote utf-8))) (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq ... save-place-version-control) (quote never)) ((eq ... save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer)))))
  my-save-place-alist-to-file()
  kill-buffer(#<buffer  *temp*-437350>)
  #f(compiled-function () #<bytecode 0x1c65c35>)()
  pp-to-string((("/home/.../test.txt" . 33)))
  pp((("/home/.../test.txt" . 33)) #<buffer  *Saved Places*>)
  (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer)))
  (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq (quote never) save-place-version-control) (quote never)) ((eq (quote nospecial) save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer))))
  (let ((file (expand-file-name save-place-file)) (coding-system-for-write (quote utf-8))) (save-current-buffer (set-buffer (get-buffer-create " *Saved Places*")) (delete-region (point-min) (point-max)) (if save-place-forget-unreadable-files (progn (save-place-forget-unreadable-files))) (insert (format ";;; -*- coding: %s -*-\n" (symbol-name coding-system-for-write))) (let ((print-length nil) (print-level nil)) (pp save-place-alist (current-buffer))) (let ((version-control (cond ((null save-place-version-control) nil) ((eq ... save-place-version-control) (quote never)) ((eq ... save-place-version-control) version-control) (t t)))) (condition-case nil (write-region (point-min) (point-max) file) (file-error (message "Saving places: can't write %s" file))) (kill-buffer (current-buffer)))))
  my-save-place-alist-to-file()
...

Я уже много чего пытался исправить. Мое первое предположение состояло в том, что последний вызов (kill-buffer (current-buffer)) приведет к бесконечной рекурсии. Но его удаление не помогает.

Подводя итог, мой вопрос:
* Почему и где происходит бесконечная рекурсия?

1 Ответ

0 голосов
/ 29 апреля 2020

Я попробовал то, что упомянул @choroba, добавив

(let 'kill-buffer-hook nil
...
) 

вокруг всей детали после (save-place-to-alist), что действительно устранило проблему бесконечной рекурсии! Но затем возникла другая проблема: этот перехваченный вызывался каждый раз, когда я переключал буферы, какая клавиша появлялась вверх и вниз и во многих других случаях. Каждый раз пишу ~/.emacs.d/places. Так что это было не то, что я хотел.

Тем временем я нашел удобное решение: добавив функцию не к kill-buffer-hook , но к after-save-hook. Для меня этого достаточно:)

Моя последняя save-place -установка, которая прекрасно работает для меня, теперь выглядит следующим образом:

(defun my-save-place-alist-to-file ()
  (interactive)
  (save-place-to-alist)
  (let ((file (expand-file-name save-place-file))
        (coding-system-for-write 'utf-8))
    (with-current-buffer (get-buffer-create " *Saved Places*")
      (delete-region (point-min) (point-max))
      (when save-place-forget-unreadable-files
        (save-place-forget-unreadable-files))
      (insert (format ";;; -*- coding: %s -*-\n"
                      (symbol-name coding-system-for-write)))
      (let ((print-length nil)
            (print-level nil))
        (pp save-place-alist (current-buffer)))
      (let ((version-control
             (cond
              ((null save-place-version-control) nil)
              ((eq 'never save-place-version-control) 'never)
              ((eq 'nospecial save-place-version-control) version-control)
              (t
               t))))
        (condition-case nil
            ;; Don't use write-file; we don't want this buffer to visit it.
            (write-region (point-min) (point-max) file nil) ; 4th arg nil means: do not append!
          (file-error (message "Saving places: can't write %s" file))
          (kill-buffer (current-buffer)))))))

(use-package saveplace
  :config
  (save-place-mode t)
  (add-hook 'after-save-hook 'my-save-place-alist-to-file)) ; after-save-hook seems to be the best place for this
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...