Skip to content

Commit 780074b

Browse files
committed
Switch to asynchronous racer command with timeouts.
This commit replaces blocking `call-process` with asynchronous `make-process`. Instead we block explicitly until racer process output is received or timeout fires. To that effect we introduce two new custom variables `racer-command-timeout` and `racer-eldoc-timeout`. The latter is important because Eldoc runs every time Emacs is idle but the user should be able to start typing any time without waiting on the racer process. Timeout value of nil will wait for the output indefinitely. I observed that the first time `racer` shell process runs it may take a while to respond probably due to indexing. Following responses tend to be snappy. For that reason and because user asking for completion is likely ok with a bit of waiting `racer-command-timeout` defaults to nil. `racer-eldoc-timeout` however should be fairly low. How low depends on your machine, etc. Value of 0.1 was too short on my machine, but 0.5 seems to work fairly reliably. Hopefully fixes racer-rust#97
1 parent 22636dd commit 780074b

File tree

2 files changed

+55
-17
lines changed

2 files changed

+55
-17
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ Use <kbd>M-x racer-describe</kbd> to open the help buffer.
9494
For automatic completions, customize `company-idle-delay` and
9595
`company-minimum-prefix-length`.
9696

97+
Racer process may be slow to respond for instance when indexing. You can
98+
customize `racer-command-timeout` and `racer-eldoc-timeout` to avoid rendering
99+
your Emacs session unresponsive. Eldoc timeout should be on the lower side and
100+
defaults to 0.5 seconds. You can probably tweak it down on a fast machine.
101+
Timeout of `nil` will wait indefinitely.
102+
97103
### Testing your setup
98104

99105
To test **completion**: Open a rust file and try typing ```use

racer.el

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -227,30 +227,55 @@ Evaluate BODY, then delete the temporary file."
227227
(insert-file-contents-literally file)
228228
(buffer-string)))
229229

230+
(defmacro racer--with-temp-buffers (buffer-names &rest body)
231+
(declare (indent 1))
232+
`(let ((kill-buffer-query-functions nil))
233+
,@(-reduce-r-from (lambda (buffer body)
234+
(list
235+
`(with-temp-buffer
236+
(setq ,buffer (current-buffer))
237+
,@body)))
238+
body
239+
buffer-names)))
240+
241+
(defcustom racer-command-timeout nil
242+
"Abandon completion if racer process fails to respond for that
243+
many seconds (maybe float). nil means wait indefinitely."
244+
:type 'number
245+
:group 'racer)
246+
230247
(defun racer--shell-command (program args)
231-
"Execute PROGRAM with ARGS.
232-
Return a list (exit-code stdout stderr)."
233-
(racer--with-temporary-file tmp-file-for-stderr
234-
(let (exit-code stdout stderr)
235-
;; Create a temporary buffer for `call-process` to write stdout
236-
;; into.
237-
(with-temp-buffer
238-
(setq exit-code
239-
(apply #'call-process program nil
240-
(list (current-buffer) tmp-file-for-stderr)
241-
nil args))
242-
(setq stdout (buffer-string)))
243-
(setq stderr (racer--slurp tmp-file-for-stderr))
248+
"Execute PROGRAM with ARGS. Return a list (exit-code stdout
249+
stderr)."
250+
(racer--with-temp-buffers (stdout stderr)
251+
(let (exit-code
252+
stdout-result
253+
stderr-result
254+
(proc (make-process :name "*async-racer*"
255+
:buffer stdout
256+
:command (cons program args)
257+
:connection-type 'pipe
258+
:stderr stderr))
259+
(start-time (float-time)))
260+
(while
261+
(and (process-live-p proc)
262+
(with-local-quit
263+
(accept-process-output proc racer-command-timeout))))
264+
(when (process-live-p proc) (kill-process proc))
265+
(setq exit-code (process-exit-status proc)
266+
stderr-result (with-current-buffer stderr (buffer-string))
267+
stdout-result (with-current-buffer stdout (buffer-string)))
244268
(setq racer--prev-state
245269
(list
246270
:program program
247271
:args args
248272
:exit-code exit-code
249-
:stdout stdout
250-
:stderr stderr
273+
:stdout stdout-result
274+
:stderr stderr-result
251275
:default-directory default-directory
252276
:process-environment process-environment))
253-
(list exit-code stdout stderr))))
277+
(list exit-code stdout-result stderr-result))))
278+
254279

255280
(defun racer--call-at-point (command)
256281
"Call racer command COMMAND at point of current buffer.
@@ -836,13 +861,20 @@ If PATH is not in DIRECTORY, just abbreviate it."
836861
(concat "./" (f-relative path directory))
837862
(f-abbrev path)))
838863

864+
(defcustom racer-eldoc-timeout 0.5
865+
"Abandon Eldoc hinting if racer process fails to respond for
866+
that many seconds (maybe float)."
867+
:type 'number
868+
:group 'racer)
869+
839870
(defun racer-eldoc ()
840871
"Show eldoc for context at point."
841872
(save-excursion
842873
(racer--goto-func-name)
843874
;; If there's a variable at point:
844875
(-when-let* ((rust-sym (symbol-at-point))
845-
(comp-possibilities (racer-complete))
876+
(comp-possibilities (let ((racer-command-timeout racer-eldoc-timeout))
877+
(racer-complete)))
846878
(matching-possibility
847879
(--find (string= it (symbol-name rust-sym)) comp-possibilities))
848880
(prototype (get-text-property 0 'ctx matching-possibility))

0 commit comments

Comments
 (0)