Skip to content
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

Refine flycheck-display-errors lifecycle #1972

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

wyuenho
Copy link
Contributor

@wyuenho wyuenho commented Aug 15, 2022

This PR fixes a 7-8 year-old bug where the flycheck-display-error-at-point-timer has been calling flycheck-display-errors-function with error overlays marked for deletion, so even when an error has been fixed, this particular code path will still display the fixed error in the echo area.

Reproduction:

  1. Install flycheck, do not configure it at all.
  2. Turn on flycheck-mode on any elisp buffer.
  3. Make a syntax error such as
    (de |fun foo ())
  4. Observe flycheck has highlighted de and fun and there's a reference to free variable 'fun' message displayed in the echo area.
  5. Press backspace to fix the error so it becomes (defun foo ())
  6. Observe the highlighting on is gone on the symbol, but the message is being displayed in the echo area.

Expectation:

After the error has been fixed, the stale error message should not continue to display in the echo area.

@cpitclaudel
Copy link
Member

I think I see the error; however, I don't think this fix is right: (flycheck-delete-marked-overlays) is delayed to avoid flickering, and indeed this patch reintroduces flickering when a change does not fix an error (the overlays disappear and subsequently reappear).

Additionally, I'm not positive that not showing the error is the right thing to do: if I fix one error but another one persists (until the checker returns), shouldn't we still display that error?

@wyuenho
Copy link
Contributor Author

wyuenho commented Aug 16, 2022

I see your point. The problem is, there's only flycheck-display-errors-function, but not a flycheck-clear-displayed-errors-function, so all of the flycheck-display-errors-function in the world such as flycheck-postip, flycheck-posframe, flycheck-inline etc will ever only be able to display errors but not clear them when the error was fixed.....

@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch from e56ff12 to bb5f055 Compare August 16, 2022 14:08
@wyuenho
Copy link
Contributor Author

wyuenho commented Aug 16, 2022

Ok I've introduced a flycheck-clear-displayed-errors-function variable. Let me know what you think. flycheck-display-error-at-point will now call it if there are no errors to display.

@wyuenho
Copy link
Contributor Author

wyuenho commented Aug 20, 2022

After playing around with this implementation for a while, I'm quite satisfied with it. An additional benefits to this simple API is now I can finally get the error message to show with flycheck-inline when I hover on the flycheck error without dealing with the perennially broken tooltip-mode.

  (defun flycheck-show-help-function (msg)
    (when flycheck-mode
      (if (null msg)
          (flycheck-clear-displayed-errors)
        (pcase-let* ((`(,frame ,x . ,y) (mouse-position))
                     (win (window-at x y frame))
                     (`(,body-left ,body-top ,@_) (window-body-edges win))
                     (col (max 1 (- x body-left (or display-line-numbers-width 0))))
                     (row (- y body-top)))
          (with-current-buffer (window-buffer win)
            (save-excursion
              (goto-char (point-min))
              (forward-line (1- (+ (line-number-at-pos (window-start win)) row)))
              (move-to-column (1- col))
              (when-let (errors (flycheck-overlay-errors-at (point)))
                (flycheck-display-errors errors))))))))

  (add-hook 'flycheck-mode-hook
            (lambda ()
              (when (display-mouse-p)
                (if flycheck-mode
                    (setq-local show-help-function 'flycheck-show-help-function)
                  (kill-local-variable 'show-help-function)))))

@wyuenho wyuenho changed the title Delete overlays marked for deletion before finding errors from existing overlays Refine flycheck-display-errors lifecycle Aug 20, 2022
@cpitclaudel
Copy link
Member

Thanks a lot! I'm traveling this month but I can get to this early September. I hope that's OK.

@wyuenho
Copy link
Contributor Author

wyuenho commented Aug 26, 2022

Take your time!

@wyuenho
Copy link
Contributor Author

wyuenho commented Sep 24, 2022

@cpitclaudel have you had a chance to test this out?

@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch 2 times, most recently from cfa2aae to 01eaef9 Compare November 4, 2022 20:59
@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch from 01eaef9 to f470739 Compare November 21, 2022 17:36
@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch from f470739 to ddbd8e3 Compare December 15, 2022 20:31
@wyuenho
Copy link
Contributor Author

wyuenho commented Dec 15, 2022

@cpitclaudel ping again

@wyuenho
Copy link
Contributor Author

wyuenho commented Feb 25, 2023

@cpitclaudel have you had a chance to take a look at this yet?

@jcs090218
Copy link
Member

Can you rebase this, so we test it with our latest CI? Thanks!

cc @bbatsov for the review, another maintainer has the push permission.

@bbatsov
Copy link
Contributor

bbatsov commented Feb 25, 2023

I'd also suggest squashing the related commits together for the review.

@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch from ddbd8e3 to a18db30 Compare February 26, 2023 14:50
@wyuenho
Copy link
Contributor Author

wyuenho commented Feb 26, 2023

Rebased. I'm not sure what Eask is and why it is failing to download packages and breaking the tests.

I'll squash after review so you have a history to look at.

@bbatsov
Copy link
Contributor

bbatsov commented Feb 26, 2023

Rebased. I'm not sure what Eask is and why it is failing to download packages and breaking the tests.

It's replacement for Cask that's actively maintained.

@@ -3329,6 +3341,7 @@ current syntax check."
(flycheck-stop))
(flycheck-delete-all-overlays)
(flycheck-clear-errors)
(flycheck-clear-displayed-error-messages)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this something that flycheck-clear-errors should normally be doing? I find it weird to have to clear the errors and the displayed error messages separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reason as #1972 (comment). Clearing the errors data structures and displayed messages have to be distinct in order to prevent flickering.

@@ -5493,6 +5506,11 @@ non-nil."
(when flycheck-display-errors-function
(funcall flycheck-display-errors-function errors)))

(defun flycheck-clear-displayed-errors ()
"Clear errors using `flycheck-clear-displayed-errors-function'."
(when flycheck-clear-displayed-errors-function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this to be customizable? Why would users want a different behaviour?

Copy link
Contributor Author

@wyuenho wyuenho Feb 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all error messages are displayed the same way. There are many packages that adjusts how the messages are displayed, some use childframes, others use overlays. Displaying and clearing messages have to be a symmetric operation operating on the same data type in order to be reliable.

See #1972 (comment)

Copy link
Contributor Author

@wyuenho wyuenho Feb 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, see a usage example here to enable a config such as the above

@jcs090218
Copy link
Member

The CI is failing due to the upstream changes, I've opened the PR for the fix, see #2007.

@bbatsov Can you review and merge this? Thanks!

Sorry for the inconvenience! 😓

@bbatsov
Copy link
Contributor

bbatsov commented Feb 26, 2023

The fix is merged.

@cpitclaudel
Copy link
Member

This is a subtle part of flycheck. I'm very thankful for the changes and I'm sorry I haven't gotten around to reviewing them :'( Hopefully @bbatsov and @jcs090218 can test / review and report.

@wyuenho
Copy link
Contributor Author

wyuenho commented Apr 10, 2023

@bbatsov have I addressed your questions?

@wyuenho wyuenho requested a review from bbatsov April 10, 2023 10:38
@bbatsov
Copy link
Contributor

bbatsov commented Feb 4, 2024

@wyuenho Can you rebase on master, so I can see what's the current state of the CI?

:type '(choice (const :tag "Clear displayed error messages"
flycheck-clear-displayed-error-messages)
(function :tag "Clear displayed errors function"))
:package-version '(flycheck . "33")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 34, now that 33 is out.

@bbatsov
Copy link
Contributor

bbatsov commented Feb 4, 2024

Before we can merge this we also need:

  • a changelog entry
  • some entry in the user docs, so people would actual find out about this new configuration variable

@wyuenho wyuenho force-pushed the delete-marked-overlays-before-displaying-errors branch from a18db30 to a3ea819 Compare February 4, 2024 19:49
@@ -5605,6 +5613,14 @@ Hide the error buffer if there is no error under point."
(save-selected-window
(quit-window nil window)))))

(defun flycheck-clear-displayed-error-messages ()
"Clear error messages displayed by `flycheck-display-error-messages'."
(unless (null flycheck--last-displayed-message)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use when here instead?

"Clear error messages displayed by `flycheck-display-error-messages'."
(unless (null flycheck--last-displayed-message)
(if (and (stringp flycheck--last-displayed-message)
(equal (current-message) flycheck--last-displayed-message))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do a string comparison instead?

@@ -5561,6 +5565,8 @@ and if the echo area is not occupied by minibuffer input."
"Flycheck error messages"
"Major mode for extended error messages.")

(defvar flycheck--last-displayed-message nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a docstring here.

@bbatsov
Copy link
Contributor

bbatsov commented Feb 10, 2024

I left a bit of extra feedback. You'll also need to rebase this on top of master, as I was doing a lot of changes lately.

@bbatsov
Copy link
Contributor

bbatsov commented Feb 24, 2024

@wyuenho Friendly ping :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants