emacs-mini-modeline
emacs-mini-modeline copied to clipboard
With 2 window opening the same file, pressing `C-g` sometimes scrolls to the position in the other window.
First, I can say this is not a problem of mini-modeline
alone. I have an old configuration project that doesn't use mini-modeline
and it has exactly the same problem. But vanilla Emacs works well, and the problem appears after enabling mini-modeline-mode
, so I'd like to report it here and see if you have any idea. Here is how to reproduce:
-
$ emacs -Q
(require 'dash)
(require 'mini-modeline)
(mini-modeline-mode)
-
M-x delete-other-windows
to keep only one window. -
C-x C-f
to open a file. I use https://github.com/lsof-org/lsof/blob/master/main.c when testing, but it should happen with any file that's long enough. -
M-x split-window-horizontally
, so we have 2 window viewing the same file now. - Scroll one window down to somewhere.
- Hold
C-g
, or maybe press it repeatedly and quickly, then the window may go back to the starting position of the file.
If you scroll the other window to some position, and do the same thing, you'll see it actually goes near the position in the other window. Here's a screen recording:
It's a problem that confuses me for a year. I said it doesn't only happen when using mini-modeline
. I believe mode-line-bell also causes the problem (I didn't use it but has some similar code in my configuration). In my current configuration:
- I set
ring-bell-function
toignore
, and don't usemini-modeline
, problem gone. - I set
ring-bell-function
toignore
, and usemini-modeline
, problem appears. - I don't use
mini-modeline
, and use aring-bell-function
. I've created 3 versions:- Blinks the modeline: problem appears.
- Blinks the current line: problem appears.
- Blinks the echo area (just like what
mini-modeline--set-buffer-face
does, but restores it with a timer): problem gone.
I didn't do this experiment with $ emacs -Q
yet.
My best guess is:
- Doing things with the modeline (like in
mini-modeline
andmode-line-bell
) causes the problem. - Use a "window-local" visual cue (like blinking the current line) for the visible bell causes the problem.
I'm on GNU/Linux and Emacs 27.1.
After some experiment I found this line in mini-modeline--enable
causes the problem:
(setq mini-modeline--timer (run-with-timer 0 0.1 #'mini-modeline-display))
If change this to
(add-hook 'pre-redisplay-functions #'mini-modeline-display)
The problem is gone.
Now I believe the reason is keyboard-quit
, timer and the UI elements interfere with each other. This may be a problem of Emacs itself.
Edit: I found a way to simply reproduce it in $ emacs -Q
. Just run this line:
(run-with-timer 0 0.1 (lambda () (setq mode-line-format "hi")))
and open a file and do the test, it will happen. Maybe I should report this in the GNU Emacs issue tracker.
Edit: I reported it here: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44448.
The subtle bug in Emacs which caused this should be fixed now, thanks.
I must note, though, that updating the mode line with such a high frequency is not a good idea: each mode-line update sets a flag that disables display optimizations of the current buffer. So redisplay of the current buffer will work much harder, and don't be surprised if users come back complaining that your mode makes Emacs less responsive.
@Eli-Zaretskii Actually what mini-modeline-display
does is writing things to the minibuffer (not the mode-line, sorry for the inaccuracy in my report). like this:
(run-with-timer
nil 0.1
(lambda ()
(let ((buf (window-buffer (minibuffer-window nil))))
(with-current-buffer buf
(erase-buffer)
(insert "hi")))))
which could also cause this bug in vanilla Emacs. Does writing to minibuffer also has the performance problem you mentioned?
It will cause at least part of the problems, yes. What this dies is modify a non-current buffer at high frequency, so the main redisplay optimization of updating only the selected window will be disabled. And when that happens, Emacs examines all the windows on all the frames to see which ones need to be updated, something that takes more cycles.
In general, doing something that updates some stuff on display at very high frequency must cause some degradation of redisplay performance.
(Btw, the above recipe signals an error when the minibuffer is active; e.g., try "C-x C-f" after activating the timer.)
Sorry, I meant "does", not "dies".
Thanks!
What this does is modify a non-current buffer at high frequency, so the main redisplay optimization of updating only the selected window will be disabled.
Seems this is unavoidable because the whole idea of this package is to show info in the echo area. I guess what makes mode-line could update itself frequently is it's written in C, and we can't do similar things by elisp. Is that right?
Btw, the above recipe signals an error when the minibuffer is active
Yes, but you can ignore them and do the test. The actual code in this package uses a bunch of predicates to decide whether it should write to the minibuffer so it doesn't has the problem.
Seems this is unavoidable because the whole idea of this package is to show info in the echo area.
Does the info change every 100 milliseconds? If not, how about updating the echo-area only when it changes?
Anyway, if that's what the mode needs to do, so be it; I just wanted to point out the price.