joaotavora / eglot

A client for Language Server Protocol servers
GNU General Public License v3.0
2.27k stars 200 forks source link

Squiggly lines in company in certain scenarios #388

Closed brainplot closed 4 years ago

brainplot commented 4 years ago

Hi, I'm not sure if this is something to do with eglot (which talks to Flymake) or with company but I've noticed that in certain scenarios the whole list of completions gets a squiggly line underneath each entry, as in the screenshot below:

Screenshot_20191230_221541

In this case it happens when a type only a . after an object's identifier. Typing even just one letter fixes the problem, as below:

Screenshot_20191230_221713

The same thing happens with Rust but it's a bit more quirky. I get either red or green lines and I'm not exactly sure why:

Screenshot_20191230_221821

Screenshot_20191230_221810

Is there any way to fix this? And again, I'm sorry if this is not the right place to ask but I'm really confused as to which package is at fault here.

Other than this, eglot is working flawlessly for me. Thanks for the great work! :)

joaotavora commented 4 years ago

Is there any way to fix this? And again, I'm sorry if this is not the right place to ask but I'm really confused as to which package is at fault here.

I'm not sure, either. If it's Flymake, I'm the person responsible for that too, so you're not too far off the mark. This might be a problem of company-mode, though, so let's ping @dgutov

dgutov commented 4 years ago

Is that the latest company-mode?

I wonder if someone could reproduce that without Eglot (I don't have the Rust toolchain installed).

joaotavora commented 4 years ago

I'm not sure if it's remotely related, but ocasionally, I see strange company-mode behaviour when editing, say, commit messages in the *vc-log* buffer. In that buffer there is no flymake mode. The behaviour I sometimes get is garbled completion lines, as if the newline wasn't applied at the correct spot. It doesn't bother me a lot, and I have no reliable way of reproducing. It's amazing that the overlay tricks that company uses work as well as they do, tbh.

joaotavora commented 4 years ago

In the case of this particular issue, it looks like company is somehow overextending a legit flymake error overlay, by inserting text next to its end. Maybe Flymake could make the overlays behave differently (but I fear that would have other impacts, maybe, maybe not). But I'm not sure that company is indeed adding text to the buffer (is it?).

dgutov commented 4 years ago

The behaviour I sometimes get is garbled completion lines, as if the newline wasn't applied at the correct spot.

Is that with the most recent version? Too bad about no stable repro.

In the case of this particular issue, it looks like company is somehow overextending a legit flymake error overlay, by inserting text next to its end.

Right, and I have a guess that it might be related to this commit: https://github.com/company-mode/company-mode/commit/cf2d50b81be361675a7ffec3b1854ff39c1942b0

But I haven't been able to reproduce to bug, and that's kind of necessary to fix it.

But I'm not sure that company is indeed adding text to the buffer (is it?).

It does not. It uses display or after-string overlay properties.

dgutov commented 4 years ago

@brainplot Please also make sure that you're using either Emacs 26, or a very recent snapshot of Emacs 27.

joaotavora commented 4 years ago

@dgutov, I don't think I'm using that commit, I'm using https://github.com/company-mode/company-mode/commit/65fd3685e627b9b45535c6251e633795c4cbd43d (which was whatever was there when I last had to touch or debug company-mode).

I'll make sure to update to the latest version and keep an eye out for problems.

joaotavora commented 4 years ago

But I haven't been able to reproduce to bug, and that's kind of necessary to fix it.

It's pretty useful, but not strictly necessary. With these kinds of things, I normally take the snail-debugging route, asking the reporter to report on the results of carefully planned tests. Eli has does it all the time, it's slow but can lead to good results. ¯_(ツ)_/¯

dgutov commented 4 years ago

In this case writing a repro will probably take less time and effort from everybody involved.

dgutov commented 4 years ago

(which was whatever was there when I last had to touch or debug company-mode)

In which case your problem is either already fixed, or old and has been there for a while. Either way is pretty reassuring. :-)

dgutov commented 4 years ago

Oh, BTW @brainplot if you are using Emacs 27, you really need the latest company-mode version from MELPA.

joaotavora commented 4 years ago

In this case writing a repro will probably take less time and effort from everybody involved.

If the repro involves installing Rust+Rls, it's up to you to say if that's acceptable effort. At the moment it isn't, for me personally.

brainplot commented 4 years ago

Sorry for the late replay but I was trying to get flymake working without starting eglot, which I failed to.

Oh, BTW @brainplot if you are using Emacs 27, you really need the latest company-mode version from MELPA.

I'm using Arch Linux, which is a rolling release Linux distribution, and has all packages updated to the latest stable version.

$ emacs --version
GNU Emacs 26.3
Copyright (C) 2019 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

It's not because of laziness but I don't really want to maintain a self-built version of Emacs when my distro provides a recent and stable version :)

I use use-package and, for reference, this is how I configured company and eglot (and yasnippet, since I integrated it in the company-backends):

(use-package eglot
  :bind (("C-c l" . eglot)
         :map eglot-mode-map
         ("C-c f" . eglot-format))
  :config
  (add-to-list 'eglot-stay-out-of 'company)
  (add-to-list 'eglot-server-programs
               '(c++-mode . ("clangd"
                             "--background-index"
                             "--compile-commands-dir=build"
                             "--header-insertion=never"
                             "--pch-storage=memory"
                             "-j=6"))))
(use-package company
  :demand
  :bind (:map company-active-map
              ("RET")
              ("<return>")
              ("M-p" . (lambda () (interactive) (company-complete-common-or-cycle -1)))
              ("M-n" . (lambda () (interactive) (company-complete-common-or-cycle)))
              ("<tab>" . company-complete-selection))
  :custom
  (company-idle-delay 0.2)
  (company-minimum-prefix-length 2)
  (company-backends '((company-capf :with company-yasnippet)
                      company-semantic
                      company-files
                      company-dabbrev
                      company-cmake
                      (company-dabbrev-code company-keywords)))
  :config
  (global-company-mode))
(use-package yasnippet
  :hook (prog-mode . yas-minor-mode)
  :config
  (yas-reload-all))

I read the discussion and I would like to add that this issue also happens with a C++ buffer with elgot and clangd, and not only with Rust.

I usually don't use flymake-mode by itself. I always use it in conjunction with eglot (eglot takes care of enabling it of course). company-mode is always active instead, as shown in my config. I tried enabling flymake-mode in the *scratch* buffer, without eglot enabled and I didn't see the problem occurring:

Screenshot_20191231_174122

This might suggest that eglot is at fault. However, trying to use eglot and company in a Python buffer, in a similar way as with a C++ or Rust buffer above, doesn't show the same issue:

Screenshot_20191231_174427 (This is just a main.py file in my home directory, it doesn't belong to any project)

As I was mentioning earlier, I tried getting flymake working in a C++ buffer without enabling eglot and using company-clang but I couldn't do it because flymake looks for a Makefile, which I don't have since my project is managed by CMake. Sadly I've never learned how to properly write them :smile:

If there's anything I can do to help narrow down the problem, do let me know!

EDIT: Forgot to mention, all packages from package.el are updated to the latest version.

dgutov commented 4 years ago

Hmm, okay! I managed to reproduce it.

The good news is that it's not affected by the commit I mentioned above, and that flymake faces are somewhat special here because they are set by an overlay with certain priority.

What I don't understand, however, if why syntax error in emacs-lisp-mode have priority (nil . 43) (and this bug does not reproduce there), but an error in c++-mode, assigned by Eglot, has a flat priority value of 53.

dgutov commented 4 years ago

Here's a patch to try:

diff --git a/company.el b/company.el
index 035c7de..e36594d 100644
--- a/company.el
+++ b/company.el
@@ -2947,6 +2947,7 @@ Returns a negative number if the tooltip should be displayed above point."
         (overlay-put ov 'after-string disp)
         (overlay-put ov 'invisible t))
       (overlay-put ov 'face 'default)
+      (overlay-put ov 'priority 111)
       (overlay-put ov 'window (selected-window)))))

 (defun company-pseudo-tooltip-guard ()

111 because Flycheck seems to trigger the same problem, only its error overlays have priority 110. :roll_eyes:

dgutov commented 4 years ago

@cpitclaudel Any idea about Flycheck's priorities?

dgutov commented 4 years ago

Should be fixed with the current company master.

joaotavora commented 4 years ago

Great. Closing here.

joaotavora commented 4 years ago

And happy new year! :tada:

dgutov commented 4 years ago

Happy new year to all!