Closed simon-katz closed 2 years ago
I should have said, I noticed this when using flycheck-next-error
and flycheck-previous-error
. (More realistic than next-line
.)
Sorry for the dribs and drabs… This is with GNU Emacs 26.3 on macOS 10.15.7 (Catalina).
I've investigated. Looks like it's a general Emacs issue with (add-hook 'post-command-hook ...)
.
I guess I need to report this to the Emacs maintainers. When I've done that I'll add a comment here. Closing this now.
Reported as an Emacs bug at https://debbugs.gnu.org/cgi/bugreport.cgi?bug=50042
@simon-katz I'd try recent emacs versions as well, like emacs 27 or even 28 to check if it was fixed
@ericdallo I did try Emacs 27 — not fixed.
The Emacs bug report (link above) has a response suggesting it hasn't been fixed since then, either.
I've hacked a fix that wraps a sit-for
inside a run-at-time
. Seems to work OK.
(Permalink in case I change things: https://github.com/simon-katz/nomis-emacs-configuration/blob/be54e829bd91b6f218884dcc54bce62c1f795d5a/emacs-installation/emacs-init-files/nomis-fix-post-command-hook-slow-with-m-x-commands.el#L1)
This is now fixed in Emacs — at commit https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=00a9c50ad7c82f72b422100624f7f125d717c00f
The commit makes some changes to execute-extended-command
.
If, like me, you don't want to wait for Emacs 28, you can use this (copied from https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/simple.el?id=00a9c50ad7c82f72b422100624f7f125d717c00f#n2197):
(defvar execute-extended-command--binding-timer nil)
(defun execute-extended-command (prefixarg &optional command-name typed)
;; Based on Fexecute_extended_command in keyboard.c of Emacs.
;; Aaron S. Hawley <aaron.s.hawley(at)gmail.com> 2009-08-24
"Read a command name, then read the arguments and call the command.
To pass a prefix argument to the command you are
invoking, give a prefix argument to `execute-extended-command'."
(declare (interactive-only command-execute))
;; FIXME: Remember the actual text typed by the user before completion,
;; so that we don't later on suggest the same shortening.
(interactive
(let ((execute-extended-command--last-typed nil))
(list current-prefix-arg
(read-extended-command)
execute-extended-command--last-typed)))
;; Emacs<24 calling-convention was with a single `prefixarg' argument.
(unless command-name
(let ((current-prefix-arg prefixarg) ; for prompt
(execute-extended-command--last-typed nil))
(setq command-name (read-extended-command))
(setq typed execute-extended-command--last-typed)))
(let* ((function (and (stringp command-name) (intern-soft command-name)))
(binding (and suggest-key-bindings
(not executing-kbd-macro)
(where-is-internal function overriding-local-map t)))
(delay-before-suggest 0)
(find-shorter nil))
(unless (commandp function)
(error "`%s' is not a valid command name" command-name))
;; Some features, such as novice.el, rely on this-command-keys
;; including M-x COMMAND-NAME RET.
(set--this-command-keys (concat "\M-x" (symbol-name function) "\r"))
(setq this-command function)
;; Normally `real-this-command' should never be changed, but here we really
;; want to pretend that M-x <cmd> RET is nothing more than a "key
;; binding" for <cmd>, so the command the user really wanted to run is
;; `function' and not `execute-extended-command'. The difference is
;; visible in cases such as M-x <cmd> RET and then C-x z (bug#11506).
(setq real-this-command function)
(let ((prefix-arg prefixarg))
(command-execute function 'record))
;; Ensure that we never have two of the suggest-binding timers in
;; flight.
(when execute-extended-command--binding-timer
(cancel-timer execute-extended-command--binding-timer))
;; If this command displayed something in the echo area; then
;; postpone display our suggestion message a bit.
(when (and suggest-key-bindings
(or binding
(and extended-command-suggest-shorter typed)))
(setq delay-before-suggest
(cond
((zerop (length (current-message))) 0)
((numberp suggest-key-bindings) suggest-key-bindings)
(t 2)))
(when (and extended-command-suggest-shorter
(not binding)
(not executing-kbd-macro)
(symbolp function)
(> (length (symbol-name function)) 2))
;; There's no binding for CMD. Let's try and find the shortest
;; string to use in M-x.
(setq find-shorter t))
(when (or binding find-shorter)
(setq execute-extended-command--binding-timer
(run-at-time
delay-before-suggest nil
(lambda ()
;; If the user has typed any other commands in the
;; meantime, then don't display anything.
(when (eq function real-last-command)
;; Find shorter string.
(when find-shorter
(while-no-input
;; FIXME: Can be slow. Cache it maybe?
(setq binding (execute-extended-command--shorter
(symbol-name function) typed))))
(when binding
(with-temp-message
(format-message "You can run the command `%s' with %s"
function
(if (stringp binding)
(concat "M-x " binding " RET")
(key-description binding)))
(sit-for (if (numberp suggest-key-bindings)
suggest-key-bindings
2))))))))))))
My lsp-ui sideline is slow to update (takes around 2 seconds) after executing a command using
M-x ...
, but almost instant when I execute the same command using the keyboard.For example,
M-x next-line
is slow, but down-arrow is fast.The video below shows this.
I've tried this using https://github.com/emacs-lsp/lsp-mode/blob/master/scripts/lsp-start-plain.el and I get the same behaviour.
https://user-images.githubusercontent.com/823295/129334388-bfb22609-174f-48a2-9675-ba67cb57be10.mp4