jorgenschaefer / elpy

Emacs Python Development Environment
GNU General Public License v3.0
1.89k stars 259 forks source link

Typing in strings become very slow with semantic-mode enabled #1462

Open Yevgnen opened 6 years ago

Yevgnen commented 6 years ago

Summary

With semantic-mode enabled, typing in python strings becomes very slow.

Disabling either elpy-mode or semantic-mode solved the issue. I'm not sure whether it's elpy's issue...

profiler-start with cpu gives

- ...                                                            1397  76%
   Automatic GC                                                  1391  76%
 + minibuffer-complete                                              4   0%
 + elpy-rpc                                                         2   0%
+ timer-event-handler                                             253  13%
+ command-execute                                                 160   8%
+ redisplay_internal (C function)                                  11   0%

Steps to reproduce

Open a new Python file, typing something(or press a key for a while) in the strings.

My configuration

OS

macOS 10.13.4

Result of (elpy-config)

Virtualenv........: None
RPC Python........: 3.6.6 (/usr/local/var/pyenv/shims/python)
Interactive Python: python3 (/usr/local/var/pyenv/shims/python3)
Emacs.............: 26.1
Elpy..............: 1.24.0
Jedi..............: 0.12.1
Rope..............: 0.10.7
Autopep8..........: Not found (1.4 available)
Yapf..............: 0.22.0 (0.24.0 available)
Black.............: Not found (18.6b4 available)
Syntax checker....: flake8 (/usr/local/var/pyenv/shims/flake8)

Elpy configuration in my init.el

(package-initialize)
(require 'use-package)
(require 'company)
(setq company-idle-delay 0.1
      company-echo-delay 1
      company-auto-complete t
      company-auto-complete-chars "?<>:\"'"
      company-require-match nil
      company-minimum-prefix-length 2
      company-show-numbers t
      company-selection-wrap-around nil
      company-tooltip-align-annotations t
      company-dabbrev-minimum-length 2
      company-dabbrev-code-modes t
      company-dabbrev-other-buffers t
      company-backends '(company-files
                         (company-keywords
                          company-capf
                          company-dabbrev-code)
                         company-dabbrev
                         company-yasnippet)
      company-transformers '(company-sort-by-backend-importance)
      company-global-modes '(not message-mode help-mode inferior-python-mode))
(global-company-mode)

(require 'semantic)
(add-hook 'python-mode-hook #'semantic-mode)

(use-package elpy
  :ensure t
  :diminish elpy-mode
  :after python
  :init
  (setq elpy-modules
        '(elpy-module-company
          elpy-module-eldoc
          elpy-module-pyvenv
          elpy-module-sane-defaults)
        elpy-shell-echo-input nil
        elpy-shell-echo-output 'when-shell-not-visible)

  :config
  (elpy-enable))

Updated:

I find the same issue when there's a buffer created by run-python with ipython in buffer list. Typing becomes very slow in the strings in original buffer. Disabling elpy-mode solved the issue.

The issue does not exist if the run-python with python.

galaunay commented 5 years ago

Could be due to #1403.

I will make the feature optional, to avoid that kind of issues. It should be fixed as soon as #1465 is merged.

Yevgnen commented 5 years ago

@galaunay Thanks for for the quick response. I've updated elpy to elpy-20180916.839, the issue seems still there. Using describe-variable, I confirm that elpy-company-add-completion-from-shell is already set to nil. Maybe they are not related.

galaunay commented 5 years ago

Does it still happen with company mode disabled (or company-idle delay set to 1) ?

Yevgnen commented 5 years ago

The issue is gone if company-mode is disabled, while setting a large value (e.g. 1) for company-idle delay does a bit help.

galaunay commented 5 years ago

Company-mode should be disabled when you disable Elpy. Does the problem still exist if you deactivate Elpy but then re-activate company-mode ?

If it is the case, I guess the problem would come from a bad interaction between semantic and company.

If it is not the case, I guess it would be due to one of the company parameters modified by Elpy (at line 3395 in elpy.el):

     (set (make-local-variable 'company-idle-delay)
          0.01)
     ;; And annotations should be right-aligned.
     (set (make-local-variable 'company-tooltip-align-annotations)
          t)
     ;; Also, dabbrev in comments and strings is nice.
     (set (make-local-variable 'company-dabbrev-code-everywhere)
          t)
     ;; Add our own backend and remove a bunch of backends that
     ;; interfere in Python mode.
     (set (make-local-variable 'company-backends)
          (cons 'elpy-company-backend
                (delq 'company-semantic
                      (delq 'company-ropemacs
                            (delq 'company-capf
                                  (mapcar #'identity company-backends))))))
Yevgnen commented 5 years ago

company-mode is disabled if elpy-mode is disabled.

The problem does not exist if I deactivate Elpy but re-activate company-mode, the value of company-backends is

(company-files
 (company-keywords company-capf company-dabbrev-code)
 company-dabbrev company-yasnippet)

Did you see the 'update' part in my original post? An IPython process buffer also causes this issue, so I'm not sure if it is related to semantic mode.

galaunay commented 5 years ago

Alright, so it seems to me that it is linked to the way Elpy modify company behavior. So it should be gone if you deactivate elpy-module-company, i.e. using:

(setq elpy-modules
        '(elpy-module-eldoc
          elpy-module-pyvenv
          elpy-module-sane-defaults)
        elpy-shell-echo-input nil
        elpy-shell-echo-output 'when-shell-not-visible)

Is it happening ?

Yevgnen commented 5 years ago

It's gone...but I want completion....

galaunay commented 5 years ago

Yeah, sure. I am just trying to figure out where the problem comes from.

As a temporary workaround, you should be able to get the completion working by deactivating the company module (last above) and activating company manually in your config file with:

(add-hook 'python-mode-hook
          (lambda ()
            (set (make-local-variable 'company-backends)
                 (cons 'elpy-company-backend
                       (mapcar #'identity company-backends)))
            (company-mode 1)))
Yevgnen commented 5 years ago

@galaunay Works like a charm~

galaunay commented 5 years ago

Great !

If you have some time to investigate, this is the complete hooks added when you activate elpy's company module:

(add-hook 'inferior-python-mode-hook
          (lambda ()
            ;; Workaround for company bug
            ;; (https://github.com/company-mode/company-mode/issues/759)
            (setq-local company-transformers
                        (remove 'company-sort-by-occurrence
                                company-transformers))
            ;; Be sure to trigger completion for one character variable
            ;; (i.e. `a.`)
            (setq-local company-minimum-prefix-length 2)))

(add-hook 'python-mode-hook
          (lambda ()
            ;; We want immediate completions from company.
            (set (make-local-variable 'company-idle-delay)
                 0.01)
            ;; And annotations should be right-aligned.
            (set (make-local-variable 'company-tooltip-align-annotations)
                 t)
            ;; Also, dabbrev in comments and strings is nice.
            (set (make-local-variable 'company-dabbrev-code-everywhere)
                 t)
            ;; Add our own backend and remove a bunch of backends that
            ;; interfere in Python mode.
            (set (make-local-variable 'company-backends)
                 (cons 'elpy-company-backend
                       (delq 'company-semantic
                             (delq 'company-ropemacs
                                   (delq 'company-capf
                                         (mapcar #'identity
                                                 company-backends))))))
            (company-mode 1)
            (when (> (buffer-size) elpy-rpc-ignored-buffer-size)
              (message
               (concat "Buffer %s larger than elpy-rpc-ignored-buffer-size (%d)."
                       " Elpy will turn off completion.")
               (buffer-name) elpy-rpc-ignored-buffer-size))))

Apparently one of those statements is causing your issue. If you can identify which one it is, we will be able to fix the code and make the company module works again.

Yevgnen commented 5 years ago

Hi, it seems (set (make-local-variable 'company-idle-delay) 0.01) caused the issue. If I remove it, everything just fine. My personal original setting is 0.1.

galaunay commented 5 years ago

Thanks for te feedback.

After a quick try with a value of company-idle-delay of 0.1, it doesn't seems to be really slower. Maybe this would be a better default value that won't slow down Emacs.

Did you run into this issue on a particularly not powerful computer ?

Yevgnen commented 5 years ago

😅I'm on a MacBook Pro 2014 running with macOS 10.13... Yesterday the issue was still here (if 0.01) after a completely fresh installation of macOS 10.14...

galaunay commented 5 years ago

It should indeed not happen... I don't know if it is not hiding another issue, it should work fine with 0.01...

I will try to have a look.

In the meantime (that can be quite a long time...), you can reactivate elpy-company-module and overwrite elpy customisation by adding (add-hook 'elpy-mode-hook (lambda () (setq company-idle-delay 0.1))) in your config file.

mpereira commented 5 years ago

Question to the elpy maintainers: does it make sense making elpy-module-company not overwrite company variables (most importantly company-idle-delay), or at least make it optional? 0.01 makes typing really slow, and consistently causes characters to not be inputted to the buffer while typing due to the added latency of running autocomplete 1/100 of a second after every key press.

For now I'm also disabling the module but loading similar code which doesn't set company-idle-delay.

galaunay commented 5 years ago

I have nothing against using 0.1 as the default value. I use this value myself and I think it is already fast enough.

@jorgenschaefer, as the person who put 0.01 in the first place, what do you think ? Additional question: do you think the problem may be that the completion mechanism has became slower than before ?

jorgenschaefer commented 5 years ago

I really like the "suggestion as you type", and felt 0.1 was a bit slow for me, but I'm fine either way … And not sure if this got slower, but maybe some kind of debouncing or cancelling old callbacks would already work maybe? Ideally, even multiple callbacks should not make Emacs noticably slower, I don't even know why anyone would notice the callbacks queuing up.

galaunay commented 5 years ago

I put company-idle-delay to 0.1 by default (PR #1526), as the "default value that would roughly work for everyone" .

I also opened an issue (#1527) to investigate those slow downs and eventually go back to faster suggestions.

I need to check if it can be due to my latest additions to the completion system.

failable commented 5 years ago

@mpereira I agree that user custom value company-idle-delay should not be overwritten generally. For user who set it to 1.0, it seems fast as the comment in the code says ;; We want immediate completions from company.. However, for user who set it to 0.02, it gets slow down if it is set again to 0.1 and need to set back to 0.02.