racer-rust / emacs-racer

Racer support for Emacs
399 stars 48 forks source link

racer starts when cursor resting at pos 0 and locking up the UI for seconds.. #97

Closed johalun closed 5 years ago

johalun commented 6 years ago

As the title says. This is extremely annoying since the UI is frozen for seconds every time I stop with the cursor at for example pos 0 on a line like: pub struct .....

racer seem to activate if I rest with the cursor for more than ~1 second. racer is using 100% CPU for at least one second and emacs is frozen during this time.

rust/racer etc everything latest version and config according to documentation.

emacs 25.3 FreeBSD

johalun commented 6 years ago

Adding:

Setting company idle time or minimum chars does not help. This was not an issue before with the same configuration. Not sure what introduced this behavior but it could be emacs, racer or emacs packages update.

johalun commented 6 years ago

Even though I know nothing about lisp I couldn't help myself and debugged a bit. Problem seem to be that this function (setq-local eldoc-documentation-function #'racer-eldoc) is being called whenever I rest the cursor at the first letter of a word, even though I do not hook eldoc in my init file. As a consequence, racer is being called with basically wildcard search returning all it can find....

Commenting out that line at least makes Emacs usable again.

akellermann97 commented 6 years ago

The problem I think is that this uses company's capf, which blocks emacs, rather than running asynchronously. There is another company backend that doesn't block, but the backend isn't as feature complete, and though I've been using it, it really needs some tlc. But I don't know enough lisp or have enough time to spend time on that project. The link for those interested: https://github.com/emacs-pe/company-racer

vkz commented 5 years ago

Experiencing the same issue on:

GNU Emacs 26.1 (build 1, x86_64-apple-darwin14.5.0, NS appkit-1348.17 Version 10.10.5 (Build 14F2511)) of 2018-05-31

racer 2.1.19

emacs-racer commit 22636dd

I have a feeling this isn't company but Eldoc that's doing it, though. Turning it off seems to alleviate the problem. IIUC emacs-racer ends up calling #'call-process which is not async, could be that's the problem.

vkz commented 5 years ago

After some thumbing around I believe either racer complete isn't being called correctly, or it's racer, not emacs-racer that starts spinning and stalls the entire process. Say we have point (|) like so and try to replicate what racer--shell-command sends:

use std::collections::HashMap::|

command being sent to racer is

VLADILENs-MacBook-Pro-93:.emacs.d russki$ racer complete 1 31 /Users/russki/Code/try_rust/src/main.rs /Users/russki/Code/try_rust/src/main_copy.rs 
PREFIX 31,31,
^C

I observed it with edebug then replayed at command line replacing temporary substitution file with a copy of the main file so it doesn't disappear on me (any idea what this substitution file is even for?). Notice that I had to abort after waiting for a while. I don't know much about racer or enough about Rust to venture a guess here, but completing this symbol works just fine at command line:

VLADILENs-MacBook-Pro-93:.emacs.d russki$ racer complete std::collections::HashMap::
--- list of associated functions ---

FWIW I tried rewriting racer--shell-command asynchronously blocking only up to a timeout, but that surfaced another issue. I keep getting Blocking call to accept-process-output with quit inhibited!! with Eldoc enabled. Google shows up this thread https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-05/msg00722.html but I haven't dug any deeper.

Here's the code to play with:

(defmacro racer--with-temp-buffers (buffer-names &rest body)
  (declare (indent 1))
  `(let ((kill-buffer-query-functions nil))
     ,@(-reduce-r-from (lambda (buffer body)
                         (list
                          `(with-temp-buffer
                             (setq ,buffer (current-buffer))
                             ,@body)))
                       body
                       buffer-names)))

(defcustom racer-command-timeout nil
  ""
  :type 'number
  :group 'racer)

(defun racer--shell-command (program args)
  "Execute PROGRAM with ARGS. Return a list (exit-code stdout
stderr)."
  (racer--with-temp-buffers (stdout stderr)
    (let (exit-code
          stdout-result
          stderr-result
          (proc (make-process :name "*async-racer*"
                              :buffer stdout
                              :command (cons program args)
                              :connection-type 'pipe
                              :stderr stderr))
          (start-time (float-time)))
      (while (and
              (process-live-p proc)
              (< (- (float-time) start-time) (or racer-command-timeout 0.1)))
        (accept-process-output proc))
      (when (process-live-p proc) (kill-process proc))
      (setq exit-code (process-exit-status proc)
            stderr-result (with-current-buffer stderr (buffer-string))
            stdout-result (with-current-buffer stdout (buffer-string)))
      (setq racer--prev-state
            (list
             :program program
             :args args
             :exit-code exit-code
             :stdout stdout-result
             :stderr stderr-result
             :default-directory default-directory
             :process-environment process-environment))
      (list exit-code stdout-result stderr-result))))

I might look into it further if Rust clicks and I start using it more. Hope ^ wasn't completely useless. Thank you for emacs-racer.

vkz commented 5 years ago

You can "cure" the above mentioned inhibit quit warning by passing an explicit timeout to accept-process-output. At least this makes Emacs responsive with both company completions and Eldoc enabled:

(accept-process-output proc (or racer-command-timeout 0.1))
vkz commented 5 years ago

This may also alleviate #86 and #91 which didn't come up in my initial search, sadly. My experiments with command line racer show that its racer who may on occasion be terribly slow. Timeouting Eldoc lookup seems to help with Emacs unresponsiveness. Could people experiencing problems please try the PR and report back. Thanks