GNU bug report logs - #43730
27.1; Running (visual-line-mode 1) twice

Previous Next

Package: emacs;

Reported by: Miha Rihtaršič <miha <at> kamnitnik.top>

Date: Wed, 30 Sep 2020 21:15:01 UTC

Severity: normal

Tags: fixed

Found in version 27.1

Fixed in version 28.1

Done: Lars Ingebrigtsen <larsi <at> gnus.org>

Bug is archived. No further changes may be made.

Full log


Message #8 received at 43730 <at> debbugs.gnu.org (full text, mbox):

From: Lars Ingebrigtsen <larsi <at> gnus.org>
To: Miha Rihtaršič <miha <at> kamnitnik.top>
Cc: 43730 <at> debbugs.gnu.org
Subject: Re: bug#43730: 27.1; Running (visual-line-mode 1) twice
Date: Thu, 01 Oct 2020 04:15:43 +0200
Miha Rihtaršič <miha <at> kamnitnik.top> writes:

> Running (visual-line-mode 1) twice is inconsistent due to variable
> visual-line--saved-state being set twice.
>
> A real life example, producible with emacs -Q would be to run
>
> (setq-default truncate-lines t)
> (add-hook 'text-mode-hook 'visual-line-mode)
> (add-hook 'prog-mode-hook 'visual-line-mode)
>
> and visit a buffer in mhtml-mode, which runs both text-mode-hook and
> prog-mode-hook.
> visual-line-mode sets the local value of truncate-lines to nil as
> expected but turning it off with
> M-x visual-line-mode
> fails to restore truncate-lines back to t, due to incorrect
> visual-line--saved-state.

Thanks for the analysis.  It seems to me that the way to fix this
problem would be to do something general in define-minor-mode.  It has
always confused me that the resulting mode function starts like this:

       (defun ,modefun (&optional arg ,@extra-args)
         ,(easy-mmode--mode-docstring doc pretty-name keymap-sym)
	 ;; Use `toggle' rather than (if ,mode 0 1) so that using
	 ;; repeat-command still does the toggling correctly.
	 (interactive (list (or current-prefix-arg 'toggle)))
	 (let ((,last-message (current-message)))
           (,@setter
            (if (eq arg 'toggle)
                (not ,getter)
              ;; A nil argument also means ON now.
              (> (prefix-numeric-value arg) 0)))
           ,@body

This means that all the modes basically have bodies that start like this:

  (if visual-line-mode
      (progn

And the modes do not know whether the mode was already on, or whether
we're switching it on now, because the only clue it has is the value of
visual-line-mode, and that has just been set based on ARG.

So.  One really aggressive way to try to fix this would be for
define-minor-mode to just not call the body at all if the value of the
mode variable doesn't change.  That is, the second call here would do
absolutely nothing:

(visual-line-mode 1)
(visual-line-mode 1)

I think that would be logical change, but...  it's a pretty radical
change?  Who knows what it would affect?

A much less invasive change would be to bind a variable in the defun
there, like

	 (let ((,previous-state ,modevar))
            
and then modes like visual-line-mode could go

  (when (not (eq visual-line-mode previous-state))
    (if visual-line-mode
        (progn

Any opinions?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no




This bug report was last modified 4 years and 232 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.