4

This problem started happening today when I switched to my desktop computer after a couple months of using my laptop. I updated emacs to 25.3.1, updated all my packages, and downloaded my latest .emacs, the one that I had been using on my laptop.

When I run M-x magit-status, I get the following message:

user-error: Whitespace-Mode isn’t compatible with Magit.  See `magit-diff-paint-whitespace' for an alternative.

This only happens after I run (global-whitespace-mode 1) to enable visible whitespace everywhere. When I run (global-whitespace-mode 0) then I can run magit-status but lose global whitespace.

jcarpenter2
  • 227
  • 1
  • 6
  • Nothing changed on Magit's side, but three people reported this over the last 24 hours. Do you use some starter-kit? ... ah wait ... two of them are you ;-) – tarsius Feb 12 '18 at 11:36
  • Incidentally, I can't replicate this problem with the current version of Magit on MELPA. – phils Feb 13 '18 at 05:01
  • Cross-referencing with the associated issue on Github: https://github.com/magit/magit/issues/3374 – phils Feb 13 '18 at 05:02

3 Answers3

10

I just added the following to my init.el:

(defun prevent-whitespace-mode-for-magit ()
  (not (derived-mode-p 'magit-mode)))

(add-function :before-while whitespace-enable-predicate 'prevent-whitespace-mode-for-magit)

This basically advises the function whitespace-enable-predicate, which whitespace-mode uses to determine, which buffers should receive global-whitespace-mode (and which is confusingly a variable holding a function as a value, not a named function, hence the add-function instead of advice-add, and no quote in front of its name; we want the value). We just ask whether we are in a magit derived mode, here. The :before-while basically assures that in all the other cases, the original behavior of whitespace-enable-predicate is preserved; see the documentation of add-function for more details.

1

You could customize the whitespace-global-modes variable to be:

(not magit-mode)

Edit: In fact, as pointed out by Julian Kniephoff in the comments, this would have to be a more complete list of magit modes, which is pretty cumbersome, and would need maintaining. Something like:

(not
 magit-mode magit-cherry-mode magit-diff-mode magit-log-mode
 magit-log-select-mode magit-merge-preview-mode
 magit-process-mode magit-reflog-mode magit-refs-mode
 magit-repolist-mode magit-revision-mode magit-stash-mode
 magit-stashes-mode magit-status-mode magit-submodule-list-mode)

With that in mind, I couldn't really recommend this approach.


Edit 2: I don't recommend the following either (it's way too fiddly compared to just using advice), but if you particularly wanted to keep this variable populated dynamically using only hooks...

(setq whitespace-global-modes '(not magit-mode))

(defun my-inhibit-whitespace-mode-maybe ()
  "Inhibit `global-whitespace-mode' for certain modes.

Used in `after-change-major-mode-hook', but before the global
mode is processed."
  (when (derived-mode-p 'magit-mode)
    (add-to-list 'whitespace-global-modes major-mode :append)))

(defun my-global-whitespace-mode-hook ()
  "Custom behaviours for `global-whitespace-mode'."
  ;; n.b. We need `my-inhibit-whitespace-mode-maybe' to act before
  ;; `whitespace-turn-on-if-enabled' in `after-change-major-mode-hook'.
  (remove-hook 'after-change-major-mode-hook 'my-inhibit-whitespace-mode-maybe)
  (when global-whitespace-mode
    (add-hook 'after-change-major-mode-hook 'my-inhibit-whitespace-mode-maybe)))

(add-hook 'global-whitespace-mode-hook 'my-global-whitespace-mode-hook)

(global-whitespace-mode 1)
phils
  • 48,657
  • 3
  • 76
  • 115
  • I tired that, too, but it did not work for me. Probably because the typical magit buffers (like `magit-status`) are not actually in `magit-mode`, but rather in a derived mode (for example `magit-status-mode`). `whitespace-global-modes` seems to work only with exact matches. – Julian Kniephoff Feb 12 '18 at 08:41
  • Right, that makes sense. – phils Feb 12 '18 at 11:10
  • I guess you could compute the list with something like ``(let ((modes nil)) (mapatoms (lambda (m) (when (provided-mode-derived-p m 'magit-mode) (push m modes)))) `(not ,@modes))`` – npostavs Feb 13 '18 at 02:53
  • Nice idea, but I don't think it's going to deal with autoloads? – phils Feb 13 '18 at 03:57
1

Looking at whitespace.el I see we could also do this:

(with-eval-after-load 'whitespace
  (setq whitespace-enable-predicate
        `(lambda ()
           (and (funcall ,whitespace-enable-predicate)
                (not (derived-mode-p 'magit-mode))))))

This is somewhat similar to @JulianKniephoff's answer, but not using advice. However I note that advice is somewhat expected in this case, as C-h v whitespace-enable-predicate states:

This variable is normally modified via ‘add-function’.

phils
  • 48,657
  • 3
  • 76
  • 115
  • `add-function` isn't advice, it's just a fancier way of doing that kind of variable setting (e.g., a particular advantage for this case is that the `add-function` form is idempotent). – npostavs Feb 13 '18 at 12:57
  • I'm siding with the `add-function` docstring :) – phils Feb 13 '18 at 14:05
  • Hah. I would change the docstring, but I'm not sure what word to use instead of "advice" there ([Bug#25581](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25581) is kind of related). – npostavs Feb 13 '18 at 23:52