Skip to content

Prevent console from auto-scrolling to bottom#9008

Open
mjiang97 wants to merge 1 commit into
flutter:mainfrom
mjiang97:fix-issue-3778
Open

Prevent console from auto-scrolling to bottom#9008
mjiang97 wants to merge 1 commit into
flutter:mainfrom
mjiang97:fix-issue-3778

Conversation

@mjiang97

Copy link
Copy Markdown

PR Description

Prevent the logging console from auto-scrolling to the bottom when multiple errors are shown.

When a Flutter app throws a cascade of errors (e.g. an unbounded viewport), the console flooded with hundreds of lines and auto-scrolled to the bottom, burying the root-cause error at the top. This overrides scrollToEnd() in DaemonConsoleView to only scroll when the user was already at the bottom before new output arrived, preserving their position when they have scrolled up.

Fixes #3778

To verify:

  1. Run the reproduction app: https://github.com/InMatrix/flutter_error_studies
  2. Tap "Unbounded Viewport"
  3. Before: console jumps to the bottom showing hasSize assertion failures
  4. After: console stays at the top showing "Vertical viewport was given unbounded height" (the root cause)

Review the contribution guidelines below:

  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.
  • I've included the required information in the description above.
  • My up-to-date information is in the AUTHORS file.
  • I've updated CHANGELOG.md if appropriate.
Contribution guidelines:
  • See
    our contributor guide and
    the Flutter organization contributor guide
    for general expectations for PRs.
  • Larger or significant changes should be discussed in an issue before creating a PR.
  • Dart contributions to our repos should follow the Dart style guide and use
    dart format.
  • Java and Kotlin contributions should strive to follow Java and Kotlin best
    practices (discussion).

@google-cla

google-cla Bot commented Jun 22, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a mechanism in DaemonConsoleView to preserve the user's scroll position when new console output is printed, accompanied by unit tests for the scroll-end detection logic. The review feedback highlights a critical threading violation where UI components and editor geometry are accessed outside the Event Dispatch Thread (EDT). To resolve this, the reviewer suggests scheduling the scroll check on the EDT and throttling the requests using an AtomicBoolean to prevent performance degradation during rapid output.

Comment on lines +82 to +86
final Editor rawEditor = getEditor();
final EditorEx editor = rawEditor instanceof EditorEx ? (EditorEx) rawEditor : null;
if (editor != null) {
wasAtScrollEnd = isAtScrollEnd(editor);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[MUST-FIX] Accessing the Editor and its ScrollingModel (via getEditor() and isAtScrollEnd(editor)) from a background thread violates the IntelliJ Platform threading model. UI components and editor geometry must only be accessed on the Event Dispatch Thread (EDT). Doing otherwise can lead to AssertionErrors or race conditions.

We can safely schedule this check on the EDT using ApplicationManager.getApplication().invokeLater(...), throttled by the scrollCheckPending flag to avoid performance degradation during rapid output.

    if (com.intellij.openapi.application.ApplicationManager.getApplication().isDispatchThread()) {
      final Editor rawEditor = getEditor();
      final EditorEx editor = rawEditor instanceof EditorEx ? (EditorEx) rawEditor : null;
      if (editor != null) {
        wasAtScrollEnd = isAtScrollEnd(editor);
      }
    } else if (scrollCheckPending.compareAndSet(false, true)) {
      com.intellij.openapi.application.ApplicationManager.getApplication().invokeLater(() -> {
        scrollCheckPending.set(false);
        final Editor rawEditor = getEditor();
        final EditorEx editor = rawEditor instanceof EditorEx ? (EditorEx) rawEditor : null;
        if (editor != null) {
          wasAtScrollEnd = isAtScrollEnd(editor);
        }
      }, com.intellij.openapi.application.ModalityState.any());
    }

Comment on lines +62 to +64
// Whether the console was scrolled to the end before the most recent batch of output.
// Defaults to true so that the first output auto-scrolls normally.
private boolean wasAtScrollEnd = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[CONCERN] To support thread-safe scheduling of the scroll position check from background threads, we should introduce a throttled state indicator using an AtomicBoolean. This prevents flooding the Event Dispatch Thread (EDT) with redundant runnables when console output is rapid.

Suggested change
// Whether the console was scrolled to the end before the most recent batch of output.
// Defaults to true so that the first output auto-scrolls normally.
private boolean wasAtScrollEnd = true;
// Whether the console was scrolled to the end before the most recent batch of output.
// Defaults to true so that the first output auto-scrolls normally.
private boolean wasAtScrollEnd = true;
private final java.util.concurrent.atomic.AtomicBoolean scrollCheckPending = new java.util.concurrent.atomic.AtomicBoolean(false);

@helin24

helin24 commented Jun 22, 2026

Copy link
Copy Markdown
Member

Sorry I didn't reply in the issue; I didn't see your message there until now! It looks like you were able to find the relevant file to make these changes anyway; thanks!

I think the gemini comments above would be good to address. A gif/video of before and after would also be helpful.

What happens (or should happen) if a user triggers an event that produces a cascade of errors, is looking at the root cause error at the top, and then triggers another event that produces errors? Will they just stay at the first error?

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.

Stop scrolling the console to the bottom when multiple errors are shown

2 participants