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
Flycheck is stuck with custom generic checker #1592
Comments
NVM, I've migrated to flymake. |
Too bad you've closed this, since I would actually like to have a lightweight generic checker that works with LSP, and Regarding your issue, I think flycheck is getting stuck in the For LSP, I think it's better to just let the LSP backend do its stuff, and then for the Flycheck checker to report the errors as soon as they get back to Emacs from the LSP server. This is what I did for lsp-ui: In lsp-ui, errors are gathered in |
Yes, that's precisely what it does:
So, just to clarify: in Flycheck, you can't save the callback posted to
Anyhow, besides writing the proper Flycheck checker, that would require architectural changes in eglot itself - it is way too tightly tied with flymake. |
Oh you can. Asynchronous checkers (i.e., all command checkers) actually rely on this. But I'm not sure what happens when you make several calls to
Good to know. Thanks for looking into this! |
Yeah, I think this is what most probably happens there.
You're welcome! |
FWIW I have something similar to your snippet: (defun flycheck-eglot-start (checker callback)
"Run a check with CHECKER and pass the status onto CALLBACK."
(cl-labels
((flymake-diag->flycheck-err
(diag)
(pcase-let ((`(,line . ,column)
(with-current-buffer (flymake-diagnostic-buffer diag)
(save-excursion
(goto-char (flymake-diagnostic-beg diag))
(cons (line-number-at-pos)
(- (point)
(line-beginning-position)))))))
(flycheck-error-new-at
line column
(pcase (flymake-diagnostic-type diag)
(`eglot-note 'info)
(`eglot-warning 'warning)
(`eglot-error 'error))
(flymake-diagnostic-text diag)
:checker checker))))
(eglot-flymake-backend (lambda (report-fn &rest _)
(funcall callback 'finished (mapcar #'flymake-diag->flycheck-err report-fn))))))
(flycheck-define-generic-checker 'eglot
"Syntax checker using eglot.
See: `https://github.com/joaotavora/eglot'."
:start #'flycheck-eglot-start
:predicate (bound-and-true-p eglot--managed-mode)
:modes (flatten-tree (mapcar 'car eglot-server-programs))) and disable flymake from eglot (add-hook 'eglot--managed-mode-hook (lambda () (flymake-mode -1)))
|
The code above did not work for me but I made a different one based on something that I found on github: https://gist.github.com/eyal0/8f58d4209dc8cdb5d9c474b61c49b2dc I needed to modify flycheck to accept a beginning position and end position. Even if this hack isn't clean enough to be added to flycheck, I think that it would still be nice to have flycheck support another mode other than line, column, symbol, sexp, so that checkers can provide both the start and end position. |
Cool! @fmdkdd one question: Does flycheck convert those line-and-column numbers into markers in the buffer? I think that it does because when I modify the buffer, the errors seem to follow the text around correctly. It's important to follow the text around. It's kind of silly that the specification is line and column number instead of just character position because the checker that I'm using (eglot) is already providing character position. So I have to convert it to line number and column number and then flycheck is presumably converts it back in order to put a marker in the buffer. And in the converting to and from line number and column number, I have to know about tabs versus spaces and also whether the first line is 0 or 1 and the first column is 0 or 1. The interface ought to just be start-pos and end-pos. That would be great. I can understand the pain in having to support two different interfaces and the line-column interface already exists and converting everything would be too difficult by far! So at least there ought to be reliable functions to convert to and from. |
I think you'll find the (long) discussion in the linked thread informative :) We implemented that then dropped it because of backwards compatibility concerns. we want to get there eventually.
Yes, something like this? (defun flycheck-position-to-line-column (point)
"Return a (LINE . COLUMN) cons corresponding to POINT."
(let ((inhibit-field-text-motion t))
(save-excursion
(goto-char point)
(cons (line-number-at-pos) (- (point) (line-beginning-position)))))) |
Yes please. In the source code. |
@cpitclaudel Also, did you write it correctly or do you have any off-by-one errors in there? Compare with this: https://github.com/flycheck/flycheck/pull/1676/files#diff-374cdd9563b826c712b1dc6a373a0bc1R1505 |
I didn't try it :) |
Okay. After #1676 is merged, I will add the function if no one else has done it, along with some tests. I think that the correct function is this:
Need to add one. This should be tested in a file that has tabs, also, because the column is listed as |
Hello, I'll try to use your code to include eglot resutls in flycheck, but I wonder if you eventually had to/added the code above in your gist ? Should I modify it in any way or is it usable as is ? (cc doomemacs/doomemacs#3020 ) |
@gagbo Happy to help if needed |
Looks like just adding the |
That code looks suspicious: why do you have a redefinition of the flycheck-error struct? |
The original version off which I based my gist didn't have a good definition of flycheck-error. I needed the begin pos start and the begin pos end so that I could store markers instead of just integers. If you look into the history, you'll that the struct was recently changed. That change was done after I had already completed my work. Storing the start and end character positions is a lot better than storing pairs of line and column number for a few reasons:
I think that flycheck, with the latest changes, is moving toward the direction of using bite positions and markers. |
If you mean Flycheck's history, then no need to look into it: I wrote the code :)
I agree with you, but not for the reasons below ^^
Yup, that's what Flycheck's error overlays do (overlays are pairs of markers)
Can you clarify what confusion you mean? As long as the convention is clear, I don't think that's a significant issue, is it?
I do agree with that one ^^ But you still need the line and column numbers, because they are used in the error list.
We might converge on this, but I wouldn't dismiss the current design too fast; it took us a long time to come up with a version that was sufficiently backwards compatible. And one problem with markers is that they are tied to a buffer, while LSP servers will typically get batches of errors for a set of files and buffers — you want to be able to create In any case, the problem with redefining the structure is that it will break Flycheck and all other packages that depend on it, so please don't do that ^^ I'd much rather brainstorm a solution together; at the moment, I'm not sure I understand the issue clearly enough to be able to help. (As an example of suggestion: you're creating a new set of markers, but we already have those, through the overlays that we create — it would be much easier to store a buffer-local map from error objects to their overlays) |
Btw @marsam, any chance to publish your code as an extension? |
With this code there are still a few tweaks to add regarding overlays it seems :
But at least it's a lot simpler, I'll try to start again from this |
The |
Thanks for your work. |
My issue of "eglot errors swallowed somewhere" was that I didn't forcefully trigger a check in the buffer at the end or my |
Looking nice, indeed 👏! One quick tip: you should be able to use |
Indeed. Eventually @marsam snippet can be condensed into : (defun flycheck-eglot--start (checker callback)
"Clean up errors when done.
CHECKER is the checker (eglot).
CALLBACK is the function that we need to call when we are done, on all the errors."
(cl-labels
((flymake-diag->flycheck-err
(diag)
(with-current-buffer (flymake--diag-buffer diag)
(flycheck-error-new-at-pos
(flymake--diag-beg diag)
(pcase (flymake--diag-type diag)
('eglot-note 'info)
('eglot-warning 'warning)
('eglot-error 'error)
(_ (error "Unknown diagnostic type, %S" diag)))
(flymake--diag-text diag)
:end-pos (flymake--diag-end diag)
:checker checker
:buffer (current-buffer)
:filename (buffer-file-name)))))
;; NOTE: Setting up eglot to automatically create flycheck errors for the buffer.
(eglot-flymake-backend (lambda (flymake-diags &rest _)
(funcall callback 'finished (mapcar #'flymake-diag->flycheck-err flymake-diags))))
;; NOTE: Forcefully trigger a check in the buffer (function name is confusing)
(flycheck-buffer)))
(defun flycheck-eglot--available-p ()
(bound-and-true-p eglot--managed-mode))
(flycheck-define-generic-checker 'eglot
"Report `eglot' diagnostics using `flycheck'."
:start #'flycheck-eglot--start
:predicate #'flycheck-eglot--available-p
:modes '(prog-mode text-mode)) (Not using emacs-27 specific code for compatibility here). I left the |
Hi, sorry for the late response
Sure, I'm going to create an extension this weekend |
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
- Update README - Add eglot-specifics to cc, rs, py, hs removing unused lsp-mode packages when eglot is active - Add eglot-specific bindings - Add doctor warnings for debugger +lsp and +peek - Add eglot-backed lookup-handlers - Add flycheck checker using eglot for :checkers syntax users (using flycheck/flycheck#1676 and flycheck/flycheck#1592 discussion). This implementation is based on @marsam code, and uses recent Flycheck development in order to make the code smaller and easier to maintain.
I've tried using @gagbo's fix for this but flycheck just seems to hang forever when checking for errors. Emacs doesn't freeze or anything, it's just my mode-line always shows |
There really should be a way to disable commit mentions. If there's one each time I rebase a feature branch it's going to get messy quickly. I don't know what you exactly tested, but isn't the eglot checker merged in flycheck now ? If it isn't, the code used in Doom is there, the only "trick" is |
I'm not seeing a pull-request for eglot support, which PR was supposed to have merged this? I copied and pasted what you shared exactly (I think). I've got a eglot flychecker function and running S.N. you can hit unsubscribe above to the right and you'll stop recieving upate notiifications unless someone explicitly @ adds you. S.S.N. I @ added you, I'm sorry for the annoyance. |
Remove the last call to Calling manually |
The root cause for this issue ( The change happened 8 months ago joaotavora/eglot@da7ff48 So the code in flycheck-eglot doesn't run on publishDiagnostics basically. The fix is to set a variable watch on |
Since joaotavora/eglot@da7ff48, the callback defined by `eglot-flymake-backend' is only called when flymake-mode is active. To circumvent this limitation, we let-bind `flymake-mode' around `eglot-handle-notification'. Relates to flycheck/flycheck#1592 discussion
Since joaotavora/eglot@da7ff48, the callback defined by `eglot-flymake-backend` is only called when flymake-mode is active. To circumvent this limitation, we tried to let-bind `flymake-mode` around `eglot-handle-notification`. That does not work because eglot-handle-notification uses with-current-buffer macro in its implementation, and within that macro the let binding is not used anymore. It is also impossible to use setq-default in an :around advice, because the value of flymake-mode in those buffers is not-default and set to nil. Eglot starts flymake-mode on its entry-point, so +lsp-prefer-flycheck-h has to set flymake-mode to nil in order to avoid both implementations showing duplicate bindings. So instead the code of the publishDiagnostics handler is copied and the case for flycheck is manually added. Used https://github.com/joaotavora/eglot/blob/4c85df2b04e467b8ed0eca68bd202fd0e7b671f4/eglot.el#L1586 as base to patch here. Relates to flycheck/flycheck#1592 discussion
Since joaotavora/eglot@da7ff48, the callback defined by `eglot-flymake-backend` is only called when flymake-mode is active. To circumvent this limitation, we tried to let-bind `flymake-mode` around `eglot-handle-notification`. That does not work because eglot-handle-notification uses with-current-buffer macro in its implementation, and within that macro the let binding is not used anymore. It is also impossible to use setq-default in an :around advice, because the value of flymake-mode in those buffers is not-default and set to nil. Eglot starts flymake-mode on its entry-point, so +lsp-prefer-flycheck-h has to set flymake-mode to nil in order to avoid both implementations showing duplicate bindings. So instead the code of the publishDiagnostics handler is copied and the case for flycheck is manually added. Used https://github.com/joaotavora/eglot/blob/4c85df2b04e467b8ed0eca68bd202fd0e7b671f4/eglot.el#L1586 as base to patch here. Relates to flycheck/flycheck#1592 discussion
Since joaotavora/eglot@da7ff48, the callback defined by `eglot-flymake-backend` is only called when flymake-mode is active. To circumvent this limitation, we tried to let-bind `flymake-mode` around `eglot-handle-notification`. That does not work because eglot-handle-notification uses with-current-buffer macro in its implementation, and within that macro the let binding is not used anymore. It is also impossible to use setq-default in an :around advice, because the value of flymake-mode in those buffers is not-default and set to nil. Eglot starts flymake-mode on its entry-point, so +lsp-prefer-flycheck-h has to set flymake-mode to nil in order to avoid both implementations showing duplicate bindings. So instead the code of the publishDiagnostics handler is copied and the case for flycheck is manually added. Used https://github.com/joaotavora/eglot/blob/4c85df2b04e467b8ed0eca68bd202fd0e7b671f4/eglot.el#L1586 as base to patch here. Relates to flycheck/flycheck#1592 discussion
Hey.
I'm trying to write custom generic flycheck checker that works with eglot language server package, as it itself is tied to flymake and its author won't do it himself.
I've manually unhardcoded flymake calls in eglot in my local
elpa
directory (for now) and then ended up with the following code in my init.el:It seems to work all right, I can see error messages from language server in the buffer and error counter on the modeline, but there's one problem. I figured it happens when I type anything in buffer while flycheck (seemingly) is running my custom checker. The problem is that in that situation flycheck somehow gets stuck, error count in the modeline is displayed as "???" (I'm using spaceline to display flycheck error count at the modeline), and
M-x flycheck-list-errors
displays empty error list even though there are errors displayed in the buffer.I'm not that much of an elisp hacker, so I suppose there's something wrong in my code. Would you please point me at what could be wrong? Does callback passed to
:start
function require some sort of synchronization or locking?Here's additional info:
M-x flycheck-verify-setup
M-x emacs-version
: GNU Emacs 26.1 (build 1, x86_64-pc-linux-gnu) of 2018-09-29M-x flycheck-version
: Flycheck version: 32snapshot (package: 20190619.1410)Thanks in advance.
The text was updated successfully, but these errors were encountered: