9

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
  • 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
    Commented Dec 4, 2014 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
    Commented Dec 4, 2014 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
    Commented Dec 4, 2014 at 21:42

1 Answer 1

6

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.

4
  • 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
    Commented Dec 5, 2014 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
    Commented Dec 5, 2014 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
    Commented Dec 5, 2014 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. Commented Jul 29, 2016 at 3:53

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.