lsp-mode icon indicating copy to clipboard operation
lsp-mode copied to clipboard

Completion backend hangs when using Corfu as completion frontend

Open drcxd opened this issue 3 years ago • 8 comments

Thank you for the bug report

  • [X] I am using the latest version of lsp-mode related packages.
  • [X] I checked FAQ and Troubleshooting sections
  • [ ] You may also try reproduce the issue using clean environment using the following command: M-x lsp-start-plain

Bug description

Sometimes, lsp completion backend hangs when using Corfu as the completion front end.

Here is the profile:

         731  80% - corfu--post-command
         730  80%  - corfu--update
         726  80%   - corfu--update-candidates
         723  79%    - corfu--recompute-candidates
         723  79%     - corfu--all-completions
         723  79%      - completion-all-completions
         723  79%       - apply
         723  79%        - #<compiled -0x187e8d863e1757aa>
         723  79%         - completion--nth-completion
         722  79%          - completion--some
         722  79%           - #<compiled 0xf84d7d713b6baaf>
         722  79%            - orderless-all-completions
         722  79%             - orderless-filter
         722  79%              - #<compiled -0xd4df90488ccba75>
         722  79%               - #<compiled 0x9ea0f36097de3b9>
         722  79%                - lsp-request-while-no-input
         722  79%                 - sit-for
          70   7%                  + read-event
           5   0%                  + redisplay
           1   0%            completion--styles
           3   0%      redisplay
           3   0%     redisplay
           1   0%   - corfu--candidates-popup
           1   0%      corfu--popup-show
           1   0%  - corfu-quit
           1   0%   + completion-in-region-mode
         116  12% + ...
          29   3% + redisplay_internal (C function)
          17   1% - timer-event-handler
          17   1%  - apply
          17   1%   - corfu--auto-complete
          17   1%    - corfu--update
           5   0%     + corfu--update-candidates
           5   0%     + corfu-quit
           4   0%     + corfu--candidates-popup
           3   0%       redisplay
          12   1% - command-execute
          12   1%  - funcall-interactively
           8   0%   - corfu-insert
           8   0%    - corfu--insert
           8   0%     - corfu--done
           8   0%      + #<compiled -0x7aa2ac626036bae>
           4   0%   - self-insert-command
           2   0%    - tree-sitter--after-change
           2   0%       tree-sitter--do-parse
           1   0%   evil--jump-hook

More details in this issue: https://github.com/minad/corfu/issues/188

Steps to reproduce

It is quite troublesome to reproduce this issue on any computer, I am not sure could you find the problem through the profiler report. If you really need to reproduce this, please let me know and I will prepare the project.

Expected behavior

When Corfu completion is triggered, it does not hang that long. I saw that lsp-response-timeout is defined as 10.

Which Language Server did you use?

C++ with Clangd

OS

Windows

Error callstack

No response

Anything else?

No response

drcxd avatar Jun 07 '22 12:06 drcxd

Could this be another symptom of #3607?

c-alpha avatar Jul 26 '22 16:07 c-alpha

Hey, I am running into this issue, Corfu is hanging when using LSP when writing JSX in JavaScript and Typescript. I've noticed the most egregious behaviour when I start to call a component, I.E. a < followed by any character. The pause isn't guaranteed and happens semi-randomly, so it's hard for me to create a test repo. I also noticed it happening a lot when defining a self-closing element or component />. Typing / was fine, but when I tried to type >, it would freeze for multiple seconds.

justinbarclay avatar Aug 22 '22 16:08 justinbarclay

As @minad points out, there is definitely something to be fixed on the LSP Mode side.

There may be a second issue lurking though. I've had random lock-ups with Emacs 28 and 29, independent of corfu and/or lsp-mode. Single-stepping in the debugger seemed to hint to an infinite loop somewhere in the code that tries to compute the font settings.

Due to other problems ("symbol's definition is void"), I had to do a (byte-recompile-directory package-user-dir nil 'force), and have never had another lock-up since. Also, a loaddefs related patch has been pushed to Emacs 29 recently. Thus, FWIW, you might want to try the byte-recompile-directory thing and see if that changes anything for you?

Just my two cents anyway.

c-alpha avatar Aug 23 '22 13:08 c-alpha

I've got a minimal config with which this is reproducible:

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(add-to-list 'auto-mode-alist '("\\.tsx?\\'" . typescript-ts-mode))

(use-package lsp-mode
  :ensure t
  :init
  ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
  (setq lsp-keymap-prefix "C-l")
  :hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)
         (typescript-ts-mode . lsp))
  :commands lsp
  :custom
  (lsp-completion-provider :none))

(use-package corfu
  :custom
  (corfu-auto t)
  (corfu-preselect 'prompt)
  (corfu-auto-delay 0.0)
  (corfu-auto-prefix 0)
  (corfu-quit-no-match 'separator)
  (completion-styles '(basic))
  (corfu-cycle t)
  :bind
  (:map corfu-map
        ("TAB" . corfu-next)
        ([tab] . corfu-next)
        ("S-TAB" . corfu-previous)
        ("<escape>" . quit-corfu-and-exit-to-normal-mode)
        ([backtab] . corfu-previous))
  :init
  (global-corfu-mode))

Ok, I lied, there might be some corfu-related setup here that isn't required. Emacs version is 29.2, started with emacs -Q. typescript-language-server version 4.3.2, and then just open a file in a big ts repo. The problem is, that it's pretty sporadic. Whenever it happens, the Emacs process pegs one CPU core to 100%, so there seems to be something going on in the call to lsp-request-async here. The sit-for loop below that line does reliably cancel the async call after the timeout, but it waits for lsp-response-timeout seconds, and hangs Emacs completely during that time. So that leads us to one workaround for these hangups:

Set lsp-response-timeout to some very low number, like 1.

(setq lsp-response-timeout 1)

If you'd like to keep the response timeout higher elsewhere, I'd suggest add-advice with :around.

I've added some logging here and there to try and debug the issue, but no luck so far.

adimit avatar Feb 12 '24 22:02 adimit