Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

completing React components with Corfu causes Emacs to freeze #3720

Closed
3 tasks done
justinbarclay opened this issue Sep 13, 2022 · 9 comments
Closed
3 tasks done

completing React components with Corfu causes Emacs to freeze #3720

justinbarclay opened this issue Sep 13, 2022 · 9 comments
Labels

Comments

@justinbarclay
Copy link
Contributor

justinbarclay commented Sep 13, 2022

Thank you for the bug report

  • I am using the latest version of lsp-mode related packages.
  • 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

When using Corfu's auto-complete and LSP within a React application, Emacs will occasionally hang for several seconds if I start typing out a component. After waiting for several seconds, the correct list of completions will appear.

Generally, this freeze is the first character after <. So, if I entered <B, I would see < for several seconds and then <Button would show up as a completion. I've also noticed this occurs with /, >, and . but with a much lower frequency. (or I am triggering auto-complete less there)

I suspect Corfu and LSP are not playing well together because, through my limited use, I haven't been able to get Eglot to hang the same way.

Steps to reproduce

  1. Use the modified lsp-start-plain defined in this gist
  2. Clone a React application; for example, I was able to recreate the issue with this Jira Clone
  3. Run npm install to get the needed packages.
  • If you're using jira_clone this would happen in the client directory
  1. Go to a react file and try to use the component. Occasionally, not always, Emacs will freeze.

Expected behavior

I expect that Emacs will not freeze and that instead I within several hundred milliseconds I will get a completion.

Which Language Server did you use?

ts-ls

OS

Linux

Error callstack

No response

Anything else?

No response

@kiennq
Copy link
Member

kiennq commented Sep 18, 2022

@justinbarclay Can you try to replace https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-completion.el#L505-L510 with these to see if it improves your situation?

       (lambda (probe pred action)
         (cond
          ((eq action 'metadata)
           '(metadata (category . lsp-capf)
                      (display-sort-function . identity)
                      (cycle-sort-function . identity)))
          ((eq (car-safe action) 'boundaries) nil)
          (t
           (complete-with-action action (funcall candidates) probe pred))))

@justinbarclay
Copy link
Contributor Author

It's been a busy week, but I will get back to you tonight or tomorrow night.

@kiennq
Copy link
Member

kiennq commented Sep 23, 2022

Actually can you try that on the latest lsp-mode as well?

@justinbarclay
Copy link
Contributor Author

Thanks for the suggestion, @kiennq; unfortunately, Emacs still has occasional hangs during autocomplete.

@kiennq
Copy link
Member

kiennq commented Sep 26, 2022

Can you update to the latest lsp-mode and take a profiler to see where the hang is?
Alternatively, can you also evaluate the below block to see if it solves your issue?

(define-advice lsp-request-while-no-input (:around (func &rest args) no-block)
  (let ((non-essential t))
    (apply func args)))

@justinbarclay
Copy link
Contributor Author

justinbarclay commented Sep 26, 2022

Can you update to the latest lsp-mode and take a profiler to see where the hang is? Alternatively, can you also evaluate the below block to see if it solves your issue?

Sure thing, this is from typing <Menu /> and it would freeze on the /> part. I've had a more difficult time to recreate the freeze at <Me. It still does it, just less reliably.

CPU Profile

       10095  97% - ...
       10056  97%  - completion--some
       10056  97%   - #<compiled 0x784aac6fa356883>
       10056  97%    - orderless-all-completions
       10056  97%     - orderless-filter
       10056  97%      - all-completions
       10056  97%       - #<lambda -0x1dbb256db9ffa69>
       10056  97%        - cond
       10056  97%         - complete-with-action
       10056  97%          - funcall
       10056  97%           - #<lambda 0x5da1a776c3c0900>
       10056  97%            - let
       10056  97%             - catch
       10056  97%              - let
       10056  97%               - cond
       10056  97%                - let*
       10056  97%                 - lsp-request-while-no-input
          82   0%                  - sit-for
          10   0%                     #<compiled -0x17950bddfa73dcbc>
          30   0%  - if
          30   0%   - let
          30   0%    - condition-case
          30   0%     - let
          30   0%      - catch
          30   0%       - let
          30   0%        - setq
          30   0%         - or
          30   0%          - progn
          20   0%           - let
          20   0%            - let
          10   0%             - if
          10   0%              - lsp-completion--sort-completions
          10   0%               - sort
          10   0%                - #<lambda -0xb2a1edd24ee0aa8>
          10   0%                   let*
          10   0%             - -map
          10   0%              - mapcar
          10   0%               - #<lambda 0xf85e4c567da5d0c>
          10   0%                - lsp-put
          10   0%                 - or
          10   0%                  - lsp-completion--guess-prefix
          10   0%                   - let*
          10   0%                    - cond
          10   0%                       let*
          10   0%           - -map
          10   0%            - mapcar
          10   0%             - #<lambda -0xef864f2054e4dc3>
          10   0%              - lsp-completion--make-item
          10   0%               - let*
          10   0%                - progn
          10   0%                 - let
          10   0%                    let*
           9   0%    Automatic GC
          82   0% - flyspell-post-command-hook
          82   0%  - flyspell-check-word-p
          82   0%     sit-for
          76   0% - corfu--post-command
          76   0%  - corfu--update
          34   0%   - corfu--update-candidates
          34   0%    - redisplay
           7   0%     - redisplay_internal (C function)
           7   0%      - jit-lock-function
           7   0%       - jit-lock-fontify-now
           7   0%        - jit-lock--run-functions
           7   0%         - #<compiled -0x156e7ad5fbcdaac3>
           7   0%          - font-lock-fontify-region
           7   0%           - #<compiled -0xf181f8e9c83c67b>
           7   0%            - apply
           7   0%             - tree-sitter-hl--highlight-region-with-fallback
           7   0%              - tree-sitter-hl--highlight-region
           7   0%               - font-lock-fontify-keywords-region
           7   0%                - typescript--class-decl-matcher
           7   0%                   typescript--ensure-cache
          22   0%   - corfu--candidates-popup
          22   0%    - corfu--popup-show
          22   0%     - apply
          22   0%        #<compiled -0x1acdc48b2ac0bc92>
          20   0%     redisplay
          58   0% - timer-event-handler
          58   0%  - apply
          45   0%   - corfu--auto-complete-deferred
          45   0%    - corfu--update
          39   0%     - corfu--candidates-popup
          39   0%      - corfu--popup-show
          39   0%       - apply
          39   0%        - #<compiled -0x1acdc48b2ac0bc92>
          29   0%         - corfu--make-frame
          29   0%          - redisplay
          10   0%           - redisplay_internal (C function)
          10   0%            - eval
          10   0%               doom-modeline-segment--workspace-name
           9   0%           - timer-event-handler
           9   0%              apply
           6   0%     - corfu--update-candidates
           6   0%        redisplay
          13   0%   - show-paren-function
          13   0%    - show-paren--default
          13   0%       show-paren--locate-near-paren
          31   0% - redisplay_internal (C function)
          18   0%  - eval
          10   0%     doom-modeline-segment--major-mode
           8   0%   - doom-modeline-segment--buffer-info
           8   0%    - doom-modeline-update-buffer-file-state-icon
           8   0%     - doom-modeline-buffer-file-state-icon
           8   0%      - doom-modeline-icon
           8   0%         all-the-icons--function-name
          13   0%  - jit-lock-function
          13   0%   - jit-lock-fontify-now
          13   0%    - jit-lock--run-functions
          13   0%     - #<compiled -0x1568e969e41f0ac3>
          13   0%      - font-lock-fontify-region
          13   0%       - #<compiled -0xf181f8e9c83c67b>
          13   0%        - apply
          13   0%         - tree-sitter-hl--highlight-region-with-fallback
          13   0%          - tree-sitter-hl--highlight-region
          13   0%           - font-lock-fontify-keywords-region
          13   0%            - typescript--class-decl-matcher
          13   0%               typescript--ensure-cache
          10   0% - command-execute
          10   0%  - call-interactively
          10   0%   - apply
          10   0%    - call-interactively@ido-cr+-record-current-command
          10   0%     - apply
          10   0%      - #<subr call-interactively>
          10   0%         funcall-interactively

Memory Profiler

I'd share my whole memory profile but it was like 1000+ lines, so I focused on the highest percentage section

     21,314,557  47% - timer-event-handler
     21,306,925  47%  - apply
     19,341,876  43%   - corfu--auto-complete-deferred
     19,323,992  43%    - corfu--update
     16,899,603  37%     - corfu--update-candidates
     16,072,883  35%      - corfu--recompute-candidates
     16,053,775  35%       - corfu--all-completions
     16,053,775  35%        - apply
     16,053,775  35%         - completion-all-completions
     16,053,775  35%          - apply
     16,053,775  35%           - #<subr completion-all-completions>
     16,053,775  35%            - completion--nth-completion
     16,052,719  35%             - completion--some
     16,052,719  35%              - #<compiled 0x784aac6fa356883>
     16,052,719  35%               - orderless-all-completions
     16,035,759  35%                - orderless-filter
     16,028,543  35%                 - all-completions
     16,027,487  35%                  - #<lambda -0x1f8e9e5bc150d45f>
     16,027,487  35%                   - cond
     16,027,487  35%                    - complete-with-action
     15,958,975  35%                     - funcall
     15,958,975  35%                      - #<lambda -0x14bd4ce2119ef8e2>
     15,958,975  35%                       - let
     15,958,975  35%                        - catch
     15,958,975  35%                         - let
     15,958,975  35%                          - cond
     13,090,743  29%                           - let*
     13,089,687  29%                            - lsp-request-while-no-input
      9,291,631  20%                             - sit-for
      3,975,192   8%                              - #<compiled -0x17a7740114f3dcbc>
        553,737   1%                                 apply
         14,752   0%                                 #<compiled -0x1c8be91cd8f479df>
          8,640   0%                               - mapcar
          7,584   0%                                - lsp--parse-header
          3,072   0%                                   s-trim-left
          1,200   0%                               - lsp--dispatch-messages
          1,200   0%                                - run-at-time
             72   0%                                   timer-set-time
             72   0%                                 - timer-activate
             72   0%                                    timer--activate
      1,095,152   2%                              - redisplay_internal (C function)
      1,019,992   2%                               - eval
        528,456   1%                                - doom-modeline-format--main
        202,712   0%                                 - format-mode-line
        202,712   0%                                  - eval
(define-advice lsp-request-while-no-input (:around (func &rest args) no-block)
  (let ((non-essential t))
    (apply func args)))

I tried this too but it would still occasionally freeze

@kiennq
Copy link
Member

kiennq commented Sep 27, 2022

Can you toggle the io trace with M-x lsp-toggle-trace-io as well? Also, are you using gcmh or something similar? I saw the memory usage is quite high actually.
Another thing to try is using company-mode instead of corfu to see if you encounter the same problem.

I saw there's orderless-mode in your profiler, however in the lsp-start-plain there's none. Can you try without orderless-mode?

@justinbarclay
Copy link
Contributor Author

justinbarclay commented Sep 27, 2022

Also, are you using gcmh or something similar? I saw the memory usage is quite high actually.

No, no garbage collector, just a high GC threshold I guess? Looking at my config it's at 100mb, which is way higher than the 10 I thought I set it at (years ago).

Another thing to try is using company-mode instead of corfu to see if you encounter the same problem.

Company mode works great :)

Can you toggle the io trace with M-x lsp-toggle-trace-io as well?
I saw there's orderless-mode in your profiler, however in the lsp-start-plain there's none. Can you try without orderless-mode?

I will try both of these, but I am having trouble getting lsp-plain-start working on a recent version of Emac 29

@justinbarclay
Copy link
Contributor Author

So I did some more digging into this.

The issue I ran into with lsp-plain-start caused me to start playing around with Emacs versions.

For reference, I am on Arch Linux running in WSL2.

Normally I run emacs with pgtk but I was running into this issue #3738. So I downgraded to Emacs 28.2 and could not recreate this issue. I then tried upgrading to a plain version of Emacs 29, one without pgtk, and failed to recreate this issue. Finally, I tried Emacs 29 with pgtk one more time and was able to recreate this issue.

So, I believe that this issue is some edge case of Emacs 29, pgtk, and Corfu and maybe LSP because I haven't been able to recreate this using any of the 4 in isolation.

I am switching my Emacs 29 to one without pgtk. I'm going to close this issue, because its doesn't appear to be an issue with LSP but some other system (childframes in pgtk maybe?).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants