centered-cursor-mode.el
centered-cursor-mode.el copied to clipboard
ccm-position-cursor relatively expensive for post-command-hook
I'm in the process of weeding out the causes of my input latency in Emacs, and one of the minor modes that do cause some slowdown on input, but which I cannot live without either, is centered cursor mode.
The documentation for post-command-hook suggests wrapping expensive computations in (while-no-input (redisplay) ...)
. This is not possible for functions that temporarily put Emacs in an undesirable state, but to my knowledge, ccm-position-cursor
is written well enough to only ever improve the state of Emacs, meaning canceling it halfway through when we know it will execute soon enough again should be fine.
I am currently trying this out with the following piece of advice:
(define-advice ccm-position-cursor
(:around (next) cancel-recentering-on-input)
(while-no-input (redisplay) (funcall next)))
If I'm not alone in thinking this is sensible, then it might be worth wrapping the entire body of ccm-position-cursor
to prevent individual users from having to advice it. I'll try to remember to report back with my experiences after running this for a while.
If you like it, I can submit a pull request. I just don't want to implement it properly until I've had a chance to try it out for a while.
Hello,
maybe you'd like to look at the development branch (https://github.com/andre-r/centered-cursor-mode.el/tree/dev). I made some refactorings and performance improvements. One slow part was the option to not recenter at the end of buffer, I removed it for now.
I'm actually running this workaround using only vanilla Emacs features since a while back. It does cause other minor issues, though, so I might look into the dev branch if I can find the time! Thanks!
I too suffer from painful latency in a large Emacs buffer due to centered-cursor-mode. Not only every time when I open that file, but sometimes also when coming back from another buffer. While the development branch does not ameliorate the waiting times, the above define-advices does. It makes the cursor while navigating through the buffer slightly more flickering but its still much smoother than using on-board features of Emacs.
This seems like an old topic, I hope I'm not bothering you guys.
I have try (while-no-input (redisplay) ...)
, but it make my cursor blinking during holding C-n
or C-p
.
So I analysis the performance of ccm-position-cursor
, It turns out the most expensive code is count-screen-lines
from (point)
to (window-end)
(or (window-start)
), especially for distant movement of cursor in huge buffer. (This is because when distant movement happened, (point)
gives you the new position of cursor, but the window is not redisplay already, so (window-end)
or (window-start)
return the original position. That result in a huge distance for count-screen-lines
to calculate, which makes it slow. )
So I make this advice:
(defvar-local ccm-last-post-command-line-number 0)
(define-advice ccm-position-cursor
(:around (orig) cancel-recentering-on-input)
(let* ((current-line-number (line-number-at-pos (point)))
;; (current-line-number (string-to-number (format-mode-line "%l")))
;; a faster method to get line number, but there is some very tiny problem for evil-ex-search-* command.
;; see: https://emacs.stackexchange.com/questions/3821/a-faster-method-to-obtain-line-number-at-pos-in-large-buffers
(diff-line-number (abs (- current-line-number ccm-last-post-command-line-number))))
(if (< diff-line-number (round (ccm-visible-text-lines) 2))
(funcall orig)
(when (and (not (minibufferp (current-buffer)))
(equal (current-buffer) (window-buffer (selected-window))))
(recenter ccm-vpos)))
(setq ccm-last-post-command-line-number current-line-number)))
the key point is: for distant movement, just do (recenter ccm-vpos)
instead of ccm-position-cursor
.
For now, it works perfectly. Hope that helps :-) .
Hello @DeesonGao, could you make a pull request? If you like, also look at the dev branch with some unfinished optimisations (https://github.com/andre-r/centered-cursor-mode.el/tree/dev).