emacs-lsp / lsp-ui

UI integrations for lsp-mode
https://emacs-lsp.github.io/lsp-ui
GNU General Public License v3.0
1.04k stars 141 forks source link

Can't get flycheck to work with lsp-ui #226

Closed Gei0r closed 5 years ago

Gei0r commented 5 years ago

When I open a cpp file, lsp-ui with ccls does work (e.g., sideline mode). But flycheck doesn't seem to know anything about lsp-ui. flycheck-verify-setup gives:

Syntax checkers for buffer main.cpp in c++-mode:

  c/c++-clang
    - may enable: yes
    - executable: Found at c:/msys64/mingw64/bin/clang.exe

  c/c++-gcc
    - may enable: yes
    - executable: Found at c:/msys64/mingw64/bin/gcc.exe

  c/c++-cppcheck
    - may enable: Automatically disabled!
    - executable: Not found

Flycheck Mode is enabled.  Use C-u C-c ! x to enable disabled
checkers.

--------------------

Flycheck version: 32snapshot (package: 20190108.351)
Emacs version:    26.1
System:           x86_64-w64-mingw32
Window system:    w32

When I (require 'lsp-ui-flycheck), there is the following addition:

The following syntax checkers are not registered:

  - lsp-ui

Try adding these syntax checkers to `flycheck-checkers'.

How do I enable lsp-ui-flycheck?

Here's the minimal init.el:

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

(unless package-archive-contents (package-refresh-contents))  ; install use-package
(unless (package-installed-p 'use-package) (package-install 'use-package))

(eval-when-compile (require 'use-package)) (setq use-package-always-ensure t)

(use-package flycheck)
(add-hook 'c++-mode-hook 'flycheck-mode)

(use-package lsp-mode :commands lsp)
(use-package lsp-ui :commands lsp-ui-mode :hook (lsp-mode . lsp-ui-mode))
(use-package company-lsp :commands company-lsp)

(use-package ccls
  :hook ((c-mode c++-mode objc-mode) .
         (lambda () (require 'ccls) (lsp)))
  :config
  (setq ccls-executable "D:/Adrian/ccls/ccls/build/ccls.exe"))
yyoncho commented 5 years ago

Did you try (setq lsp-prefer-flymake nil) before calling lsp?

yyoncho commented 5 years ago

These are not needed:

:hook (lsp-mode . lsp-ui-mode)

(add-hook 'c++-mode-hook 'flycheck-mode)

Gei0r commented 5 years ago

OK, with setting lsp-prefer-flymake to nil it now looks better:

Syntax checkers for buffer main.cpp in c++-mode:

  lsp-ui
    - may enable: yes
    - predicate:  t

  c/c++-clang
    - may enable: yes
    - executable: Found at c:/msys64/mingw64/bin/clang.exe

  c/c++-gcc
    - may enable: yes
    - executable: Found at c:/msys64/mingw64/bin/gcc.exe

  c/c++-cppcheck
    - may enable: Automatically disabled!
    - executable: Not found

The following checker is explicitly selected for this buffer:

  lsp-ui
    - major mode: `c++-mode' supported
    - may enable: yes
    - predicate:  t

Flycheck Mode is enabled.  Use C-u C-c ! x to enable disabled
checkers.

--------------------

Flycheck version: 32snapshot (package: 20190108.351)
Emacs version:    26.1
System:           x86_64-w64-mingw32
Window system:    w32

But flycheck errors are still not displayed. For example, with this small cpp file, there's no error:

flycheck

The buffers *Flycheck errors*, *ccls* and *ccls::stderr* are all empty, fwiw.


Here's my init.el now:

(use-package flycheck)

(use-package lsp-mode :commands lsp :config (setq lsp-prefer-flymake nil))
(use-package lsp-ui :commands lsp-ui-mode)
(use-package company-lsp :commands company-lsp)

(use-package ccls
  :hook ((c-mode c++-mode objc-mode) .
         (lambda () (require 'ccls) (lsp)))
  :config
  (setq ccls-executable "D:/Adrian/ccls/ccls/build/ccls.exe"))
yyoncho commented 5 years ago

AFAIK ccls reports the errors on save.

If this does not fix your issue, can you do: (setq lsp-print-io t) and inspect the messages that are sent from the server?

Gei0r commented 5 years ago

Nothing happens on save either.

After setting lsp-print-io, I can see that the error is reported:

<<<< ccls:6988
{
  "jsonrpc": "2.0",
  "method": "textDocument/publishDiagnostics",
  "params": {
    "uri": "file:///D%3A/Adrian/ccls/testproj2/main.cpp",
    "diagnostics": [
      {
        "range": {
          "start": {
            "line": 5,
            "character": 4
          },
          "end": {
            "line": 5,
            "character": 18
          }
        },
        "severity": 1,
        "code": 2,
        "source": "ccls",
        "message": "use of undeclared identifier 'does_not_exist'"
      }
    ]
  }
}

... but it doesn't display it in the buffer.

I can see though that diagnostic messages are also produced by just typing wrong code (not only on save).

yyoncho commented 5 years ago

I just tested the same setup and it works fine.

Can you go in this file and do C-: (buffer-file-name) and C-: - (lsp--uri-to-path "file:///D%3A/Adrian/ccls/testproj2/main.cpp")

I suspect that there is filepath mismatch.

yyoncho commented 5 years ago

Change C-: to M-:

Gei0r commented 5 years ago

(buffer-file-name): "d:/Adrian/ccls/testproj2/main.cpp"

(lsp--uri-to-path "file:///D%3A/Adrian/ccls/testproj2/main.cpp"): "D:/Adrian/ccls/testproj2/main.cpp"

So there's a difference in the driver letter (D vs d).

yyoncho commented 5 years ago

as a temporary workaroud you may use:

(defun lsp--uri-to-path (uri)
  "Convert URI to a file path."
  (let* ((url (url-generic-parse-url (url-unhex-string uri)))
         (type (url-type url))
         (file (url-filename url))
         (file-name (if (and type (not (string= type "file")))
                        (if-let ((handler (lsp--get-uri-handler type)))
                            (funcall handler uri)
                          (error "Unsupported file scheme: %s" uri))
                      ;; `url-generic-parse-url' is buggy on windows:
                      ;; https://github.com/emacs-lsp/lsp-mode/pull/265
                      (or (and (eq system-type 'windows-nt)
                               (eq (elt file 0) ?\/)
                               (substring file 1))
                          file))))
    (let ((s (concat (-some 'lsp--workspace-host-root (lsp-workspaces)) file-name)))
      (concat (downcase (substring s 0 1)) (downcase (substring s 1))))))

I do not have Windows PC at hand and and it will be a bit difficult to find the proper places to fix the casing issue. Do you have elisp experience? The functions that have to be edited to fix that issue are lsp--on-diagnostics and lsp-ui-flycheck--start probably by downcasing the file time before putting in the map when OS is windows.

Gei0r commented 5 years ago

The workaround doesn't work either unfortunately.

I won't be able to look into it anymore today, but I will continue trying it out tomorrow.

I'm quite ok with elisp. Maybe you can give me a hint as to where I can start debugging the issue, i.e. what functions I should watch in the debugger etc.?

yyoncho commented 5 years ago

Here it is the list of functions:

lsp--uri-to-path - converts uri to file path lsp--on-diagnostics - the function that receives the diagnostics and puts them into a hash-map and should trigger lsp-after-diagnostics-hook

lsp-ui is subscribed to lsp-after-diagnostics-hook and gets the errors for the current file from using lsp-diagnostics and converts them to flycheck errors in lsp-ui-flycheck--start

Edit: probably conditionally downcasing the file name before putting in in the lookup map and then downcasing when looking up in lsp-ui will fix the issue.

yyoncho commented 5 years ago

Your issue is duplicate of https://github.com/emacs-lsp/lsp-mode/issues/343

Gei0r commented 5 years ago

I tried the same setup on windows and this is what I found out:

Looking through the source code, I see that the hook is supposed to be set in lsp--flymake-setup which is called from lsp--auto-configure depending on lsp-prefer-flymake.

I will continue investigating.

yyoncho commented 5 years ago

based on the description I believe that lsp--on-diagnostics does not trigger the hook, probably this returns nil: https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-mode.el#L847

Edit: by the hook I mean lsp-after-diagnostics-hook

Gei0r commented 5 years ago

I don't know what caused it on windows, but now the hooks are set up correctly. I haven't changed anything...

Also I got it to work now by sprinkling downcase-calls all over the lsp(-ui) source code. Now I'll try to figure out which ones are required.