5

I end up looking at source files of packages I have installed fairly often and want to avoid accidentally editing them while I am viewing them. After looking at https://emacs.stackexchange.com/a/3681/767, I put together this:

(dir-locals-set-class-variables
 'emacs
 '((nil . ((buffer-read-only . t)
           (show-trailing-whitespace . nil)
           (tab-width . 8)
           (eval . (whitespace-mode -1))))))
(dir-locals-set-directory-class (concat user-emacs-directory "elpa") 'emacs)
(dir-locals-set-directory-class
 (locate-dominating-file (locate-library "winner") "lisp") 'emacs)

This worked fine until I went to install a new package. At that point, the machinery kicks in to create autoloads and then fails to write them because they are considered to be read-only.

I suspect I could do something with defadvice but maybe my whole approach needs to be rethought. Has anyone else already solved this?

3
  • 1
    You can also use C-x C-q to change a buffer's read-only status. (And there's always undo ;-).)
    – Drew
    Commented Dec 17, 2018 at 18:27
  • 2
    Please M-x report-emacs-bug about the failure to install packages with such a config.
    – Stefan
    Commented Dec 17, 2018 at 19:13
  • The package hardhat can help here, too.
    – clemera
    Commented Dec 21, 2018 at 21:39

3 Answers 3

3

I worked around this before by making an exception for autoloads. From my config:

(define-derived-mode emacs-lisp-autoloads-mode emacs-lisp-mode "Autoloads"
  "Marker mode for package autoloads files.")
(add-to-list 'auto-mode-alist '("autoloads\\.el\\'" . emacs-lisp-autoloads-mode))
(add-to-list 'auto-mode-alist '("loaddefs\\.el\\'" . emacs-lisp-autoloads-mode))

(dir-locals-set-class-variables
 'read-only
 '((nil . ((buffer-read-only . t)))
   ;; Keep autoloads writeable so we can update packages
   (emacs-lisp-autoloads-mode . ((buffer-read-only . nil)))))

This defines a mode for autoloads and associates it with the typical file names. Then the dir-locals class sets the buffer to read-only, except for buffers in emacs-lisp-autoloads-mode. You can associate this 'read-only class with your elpa directory as you were doing before.

4

Adding following hack, which temporarily inhibits read-only-mode, is working for me:

(advice-add
 'package-install-from-archive
 :around (lambda (orig-fun &rest args)
           (let ((inhibit-read-only t))
              (apply orig-fun args))))

The full relevant config looks like:

(dir-locals-set-directory-class (concat user-emacs-directory "elpa") 'emacs)
(dir-locals-set-directory-class
 (locate-dominating-file (locate-library "winner") "lisp") 'emacs)
(advice-add
 'package-install-from-archive
 :around (lambda (orig-fun &rest args)
           (let ((inhibit-read-only t))
              (apply orig-fun args))))
3
  • What about just let-binding inhibit-read-only ?
    – phils
    Commented Dec 18, 2018 at 0:56
  • Sounds even better than what I came up with. I’ll give it a try tomorrow!
    – Gina White
    Commented Dec 18, 2018 at 1:43
  • inhibit-read-only worked great, I have updated the the answer with that, thank you!
    – Gina White
    Commented Dec 18, 2018 at 16:28
0

I think your config is sound. Too bad it trips up package.el. While waiting for this to be fixed, you can try the following instead:

(add-hook 'find-file-hook #'my-find-file-tweaks)
(defun my-find-file-tweaks ()
  (when (and (file-in-directory-p buffer-file-name "~/.emacs.d/elpa")
             (not delay-mode-hooks))
    (read-only-mode 1)))

where the (not delay-mode-hooks) test is an ugly hack that tries to detect the case where package.el generates the autoloads.

1
  • I don't understand how this hack is intended to work, but I gave it a try and I got the same failure (about trying to modify a read-only buffer).
    – Gina White
    Commented Dec 17, 2018 at 22:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.