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?

Gina White
  • 344
  • 2
  • 10

3 Answers3

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))))
Gina White
  • 344
  • 2
  • 10
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.

glucas
  • 20,175
  • 1
  • 51
  • 83
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.

Stefan
  • 26,154
  • 3
  • 46
  • 84
  • 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 Dec 17 '18 at 22:20