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
Support errors found in other files #1427
Conversation
|
ba19b00
to
0fe7cac
Compare
That moment when you get a PR from Steve Purcell 😍 🥇 ❤️ |
In theory I'm an admin here, but I haven't been active for ages. :-) |
I know :) Doesn't reduce the excitement to review your code ^^ |
Please lower your expectations. ;-) |
aca2f10
to
f67610f
Compare
I made a few further tweaks such that only errors from other files are shown, since in Elm - at least - warnings from other files would be displayed in the current file when not strictly necessary. In fact, a more conservative version of this change could choose to show errors from other files only if there are no errors listed for the current file. (I'd suggest it's not necessary to be so conservative.) |
3dccca5
to
108c7c6
Compare
That looks very exciting! Thank you @purcell for working on this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks really great.
I've made a few comments here and there. The main thing I'm unsure about is overlays on the first line of the file. The nice bit about that trick is that it reuses the existing navigation infrastructure quite smoothly, so I could live with it :)
It might be nice to add a few tests for navigation (previous/next-error) with other files, too.
flycheck.el
Outdated
(if id (format "%s [%s]" message id) message))) | ||
(filename (flycheck-error-filename err))) | ||
(concat (when (and filename (not (equal filename (buffer-file-name)))) | ||
(format "In \"%s\": " (file-relative-name filename default-directory))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a newline after the colon?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we show the path relative to the default directory, or to the current file? (I'm not sure whether default-directory here is the checker's :working-directory
or the current buffer's folder)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add the newline and check whether the default directory is the right one here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked and the default-directory is the correct one, i.e. it's the directory of the current buffer's file.
flycheck.el
Outdated
(let ((file-name (flycheck-error-filename err))) | ||
(and buffer-file-name file-name | ||
(not (flycheck-same-files-p buffer-file-name file-name)) | ||
(eq 'error (flycheck-error-level err))))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make the error level for other files customizable? It might be best to wait until the feature is requested, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should wait for a request.
flycheck.el
Outdated
(defun flycheck-relevant-error-other-file-p (err) | ||
"Determine whether ERR is a relevant error for another file." | ||
(let ((file-name (flycheck-error-filename err))) | ||
(and buffer-file-name file-name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to have a a buffer-file-name here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because buffer-file-name
can be nil, in which case it's not safe to call the function which checks that the files are the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but we could also not call that function in that case (if I'm editing a scratch file and that file doesn't compile because of an error in an import, I might still be interested in that error)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see! I think you're right. Will fix that in a few hours - currently at work. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
(and buffer-file-name file-name | ||
(flycheck-same-files-p file-name buffer-file-name)) | ||
;; This is a significant error from another file | ||
(flycheck-relevant-error-other-file-p err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic feels a bit convoluted: flycheck-relevant-error-other-file-p
is used in two places: here it simplifies to (eq 'error (flycheck-error-level err))
, and… (see below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, makes sense. Thanks!
(pcase-let* ((`(,beg . ,end) (flycheck-error-region-for-mode | ||
err (or flycheck-highlighting-mode 'lines))) | ||
(pcase-let* ((`(,beg . ,end) | ||
(if (flycheck-relevant-error-other-file-p err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(continued) …here it simplifies to having different file names, since the error has already been filtered. I wondered if it'd be better to inline it in both places and simplify accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it doesn't simplify to that - either the error's file or the current buffer's file name could be empty, and duplicating that logic from flycheck-relevant-error-file-p
therefore didn't feel right here. So I extracted flycheck-relevant-error-other-file-p
, with the result that that function checks the presence of those two filenames - in the context in which it is called in flycheck-relevant-error-file-p
that check is redundant.
flycheck.el
Outdated
;; Display overlays for other-file errors on the first line | ||
(cons (point-min) (save-excursion | ||
(goto-char (point-min)) | ||
(end-of-line) (point))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe point-at-eol
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
@@ -3940,7 +3965,8 @@ message to stretch arbitrarily far." | |||
message checker-name))) | |||
|
|||
(defconst flycheck-error-list-format | |||
`[("Line" 5 flycheck-error-list-entry-< :right-align t) | |||
`[("File" 6) | |||
("Line" 5 flycheck-error-list-entry-< :right-align t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It it worth adding a column to the error list, vs. adding the file name to the error message? Arguably it's nice to be able to sort by file, but in most cases it'll take space somewhat needlessly. Could we hide that column when all errors point to the same file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there are probably some things we could do here, but I'm also keen not to try to gold-plate this before it has seen use in the wild. My suggestion would be to go with this simple approach for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
;; If widening gets in the way of moving to the right place, remove it | ||
;; and try again | ||
(widen) | ||
(goto-char pos))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why that function didn't just check whether (<= (point-min) pos (point-max))
(I know it's existing code).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... good point!
108c7c6
to
3d84972
Compare
Yeah, that's what I like about it too. It's simple, and it makes those other-file errors obvious, at least.
Yep, that would be nice for completeness. The existing tests still pass, which is encouraging. ;-) |
I've pushed those couple of little fixes. |
(vector (flycheck-error-list-make-cell | ||
(if filename | ||
(file-name-nondirectory filename) | ||
"") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this reduces to (file-name-nondirectory (or filename ""))
… not sure it reads better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has the same effect and is more concise, but it calls file-name-nondirectory
unnecessarily on ""
, so I'd say keep the if
. (This came from the original PR, and I didn't find a better way to express it.)
- Include errors (but not warnings) from other files in the error list - When clicking on the error in the error list, jump to the other file - Having jumped, force a re-check if and only if the other file's buffer does not already have that error listed - Display overlays for errors from other files on the first line - When showing such errors in the echo area, show the filename
3d84972
to
aa7e6ab
Compare
I've tried really hard to find somewhere to add relevant tests, but gave up. With the PR in its current form, there's no real effect on error navigation, either in-buffer, or when clicking on items in the error list. It's not clear how best to set up a situation where errors are generated for a depended-upon file -- from what I can see, this isn't the case for the language resources used by existing tests, and there's no existing coverage of the |
So am I :) This is a great PR, and I've nitpicked enough at this point ^^ @fmdkdd, thoughts/comments? I'll merge tonight from home otherwise. |
@cpitclaudel I haven't had a chance to take a look yet. I should be able to do so in the next 24h. |
No pressure :) I just meant to confirm that I was ready for merging on my end. |
Alrighty, I'm going for it. If there are any resulting issues which appear related, please CC me into them! |
Sorry @fmdkdd - if you end up taking a closer look and find anything that bugs you, just follow up here with any feedback and I'll be happy to tinker further. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks great to me. I made just a small comment.
Adding error overlays from other files on the first line actually breaks the integration tests for Rust (and would probably affect other project-based checkers depending on the tests we have). If we want to keep that solution, we'll have to update the tests infrastructure to consider that case.
What happens if we don't add these overlays? The errors from other files still appear in the error list, and in the modeline, and are caught by next-error
, right? Would it be that confusing to not display the squiggles in that case?
In any case, I'm excited to have that feature finally land. I would have moved the changelog item much further up ;)
(goto-char pos) | ||
(user-error "No more Flycheck errors")))) | ||
(-if-let* ((pos (flycheck-next-error-pos n reset))) | ||
(let ((err (get-char-property pos 'flycheck-error))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that let
superfluous since we already have -if-let*
above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good catch. Fixed in 0ff3c72.
I personally think that the overlay on the first line is the single most important part of this change. Flycheck is most commonly used without the error-list, from what I've observed of my own and others' usage, and in that mode of usage it's not sufficient to see only the error count in the modeline: you need an overlay to jump to, and to trigger the display of the error in the echo area. It's certainly a little ad-hoc to bundle errors onto the first line, but in practical use it seems fairly optimal. Sorry it broke the Rust tests. Do they run automated somewhere? I'll happily see if I can run them locally and fix them up accordingly.
I actually went ahead and did that, too, because it makes sense to me to mention it before readers zone out. :-) |
Since GH-1427, errors from other files are included in the current buffer. So they must be included in the integration tests. In the case of Rust, macro errors emit diagnostics with a phony file, so we now filter these errors to prevent them from appearing in the buffer.
No, unfortunately they don't run automated anywhere. I've fixed them in #1433, since it was a good opportunity to refresh them.
Ah that's the crucial point. So Thank you again for pushing this :) |
Can anybody point me to how to enable this functionality? Is it meant to show up in the default list from |
@chrissound It is enabled by default, if you update Flycheck from MELPA (not stable). Errors from other files will appear on the first line of your buffer (and in the error list), provided that 1) the checker actually emits errors for other files, and 2) you have no errors in the current buffer (if you have only warnings or info messages in the current buffer, errors from other files should appear). |
@fmdkdd said:
@purcell said:
Some feedback after using this feature for a few days now: I like having the overlay on the first line for errors in other files, but I'd like to ability to jump to the overlay (with |
Well, maybe it's because you are not used to it yet? ;)
We could add an option along these lines: if it's an error from another file, jump to the in-buffer overlay, /unless/ the cursor is already on the overlay, and in that case we jump to the other file instead. Do you want to make a PR? |
On Tue, May 22, 2018 at 1:48 AM, fmdkdd ***@***.***> wrote:
I find it jarring/surprising when I'm editing one file, I try to jump to the next error, and suddenly I'm in another file.
Well, maybe it's because you are not used to it yet? ;)
Perhaps :)
I think it would be less surprising if the first jump brought to the overlay, and I then had to jump again to actually change files.
We could add an option along these lines: if it's an error from another file, jump to the in-buffer overlay, /unless/ the cursor is already on the overlay, and in that case we jump to the other file instead.
Do you want to make a PR?
Sure. I've never worked on an Emacs package locally before (I use Cask
to install flycheck). Do you have a pointer to some docs on developing
and testing Emacs packages in general, or flycheck specifically?
|
We do. The Emacs Lisp manual inside Emacs is also invaluable if you want to brush up on Elisp programming. For this specific feature, you want to look at If you want to add tests, you should add them in Do not hesitate to ask further questions. |
This options controls whether Flycheck error navigation jumps to other files immediately when the selected error is in another file. This is related to PR flycheck#1427 that added overlays on the first line of the current file when errors in other files prevent checking the current file. When the new option `flycheck-jump-to-other-file-immediately` is nil (it defaults to non-nil), error navigation in the current file moves the cursor to first-line overlay, and then you have to jump again to actually go to the other file containing the error. The idea is that it's surprising for Flycheck error navigation to change files, and stopping on the first-line overlay first makes it less surprising. There is more context for this commit here: flycheck#1427 (comment).
@fmdkdd I just submitted PR #1473 in relation to our discussion. I did not add any tests, because I don't understand how the tests work, and above @purcell mentioned he couldn't figure out where to add tests for his new first-line overlays feature. I'm testing locally with two Haskell files, where one imports the other, and the imported file doesn't type check. As part of my testing, I found a bug in I didn't ask very clearly, but when I asked about docs for developing Emacs packages, what I wanted to know was how to run my locally modified version of the package, preferably without affecting my global Emacs installation. I found good docs for that in this Stack Overflow answer, and ended up using the |
The first-line error overlays added in PR flycheck#1427 weren't handled correctly by `flycheck-first-error`, due to a bug in `flycheck-next-error-overlay-pos`, where that function assumed that `point-min` would not be part of an error overlay in the `reset` case. This bug and fix is unrelated to PR flycheck#1473, except that I ran into the bug while testing flycheck#1473.
@fmdkdd I fixed the The current specification for how Flycheck error navigation (
|
That's a good idea, please do. I've used For the rest, I'll move the discussion to #1427 directly. |
Another option for this is using
and in neither case is any change to your |
If there are no errors in the current buffer, it might be because a dependent file/buffer contains errors. Instead of not showing any errors, show errors (but not warnings/info) from other files. This is supported by flycheck, see flycheck/flycheck#1427.
This change revives the abandoned PR #1191 by @TyOverby, which in turn built on @chrisdone's PR #972 to address #966. There was some excellent feedback on #1191 by @fmdkdd in this comment, which this PR has incorporated.
buffer does not already have that error listed
The hiding of other-file errors is an ongoing source of pain for Flycheck users in some language environments (Haskell, Elm, Rust), so I'm hoping we can get something merged soon.
Having spent a few hours on this, these changes seem to work well in local testing and feel quite natural to me - I'm keen to hear any further feedback! 🎉