Such as in the built-in variable mode-line-modified which displays an asterisk in the mode line if the buffer is modified.

Specifically, I want to turn hl-line-mode off when the buffer is modified and on when it's not.

I've read the documentation about "Change Hooks", but I want hl-line-mode to toggle when I undo a change like the mode line asterisk.

  • 3
    Relevant hooks appear to be after-change-functions and first-change-hook. If, for some reason, undoing from a modified buffer to an unmodified one doesn't count as a "change" for these hooks, you could advise undo to perform the toggle.
    – Dan
    Dec 4 '14 at 17:10
  • See also the function buffer-modified-p to test for whether a modification has occurred. I am using the after-save-hook and first-change-hook to toggle a modified indicator on my tabbar.
    – lawlist
    Dec 4 '14 at 17:43
  • 3
    if the change-hooks don't work perfectly when undoing, the surest way is a post-command-hook that checks buffer-modified-p.
    – Malabarba
    Dec 4 '14 at 21:42

Building off of the comments, here are two ways to achieve what you're trying to do. (Not extensively tested, so YMMV.)

Option 1: post-command-hook

Create a function that tests whether or not the buffer is modified, and then hook it into post-command-hook:

(defun hl-line-mode-toggle-maybe ()
  "Turn on `hl-line-mode' when buffer is unmodified, turn it off
when it is modified."
  (hl-line-mode (if (buffer-modified-p) -1 1)))

(add-hook 'post-command-hook #'hl-line-mode-toggle-maybe)

The advantage is that it's pretty simple. The disadvantage is that Emacs will run this test after every single command, which seems like overkill.

Option 2: first-change-hook, after-save-hook, and undo

Create a function to turn hl-line-mode off and hook it into first-change-hook. Create a function to turn hl-line-mode on and hook it into after-save-hook. Provide after advice on undo such that it turns hl-line-mode on when an undo had returned the buffer to an unmodified state:

(defun hl-line-mode-off ()
  "Turn off `hl-line-mode'."
  (hl-line-mode -1))

(defun hl-line-mode-on ()
  "Turn off `hl-line-mode'."
  (hl-line-mode 1))

(add-hook 'first-change-hook #'hl-line-mode-off)
(add-hook 'after-save-hook   #'hl-line-mode-on)

(defadvice undo (after hl-line-when-unmodified activate)
  (unless (buffer-modified-p)
    (hl-line-mode 1)))

The advantage is that it calls these functions infrequently rather than after every command. The disadvantage is that you've had to delve into advice, and there may be other, unanticipated ways to get a buffer to an unmodified state that don't trigger the "turn hl-line-mode back on" step.

  • Ahh, yes, thanks for putting that into an answer. I ended up using the second option so as not to use a post-command-hook.
    – nanny
    Dec 5 '14 at 18:09
  • 1
    revert-buffer seems like another common case that would put the buffer in to an unmodified state. You could use the after-revert-hook to handle this one.
    – glucas
    Dec 5 '14 at 20:08
  • You'd also need some way to turn on highlighting for newly opened buffers -- perhaps the after-change-major-mode-hook?
    – glucas
    Dec 5 '14 at 20:18
  • 1
    Note that add-hook has a local parameter, so if you just want to override the behaviour in certain major modes or buffers, you can. Jul 29 '16 at 3:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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