RichTextFX icon indicating copy to clipboard operation
RichTextFX copied to clipboard

Unexpected Scrolling Behavior in CodeArea when pressing enter at first line

Open Symeon94 opened this issue 7 months ago • 3 comments

Hello,

I'm currently experiencing an issue with CodeArea when using LineNumberFactory. Below, I'll describe the observed behavior, the expected behavior, and my investigation into the issue.

Observed Behavior

When CodeArea contains enough lines to require a vertical scroll bar:

  1. If the caret is positioned at the very first character (scrolled to the top) and I press Enter, a new line is added, and the view scrolls down, making line 2 the top line.
  2. Pressing Enter again keeps line 2 at the top, while newly added empty lines appear at the top.

Expected Behavior

I have noticed that this behavior is caused by LineNumberFactory. Without the line number factory:

  • The second Enter press shifts line 3 to the top.
  • Subsequent presses continue moving lines 4, 5, 6, etc., to the top.

The behavior I am trying to achieve is no scrolling at all in this specific case. Ideally:

  • If the view is scrolled to the top-most position and the caret is placed on the first line, pressing Enter should not scroll. Line 1 should remain at the top.

Investigation

I am currently analyzing the code to determine where this scrolling behavior occurs when pressing Enter. My goal is either to fix the behavior or implement a workaround for my use case.

I thought someone here might have insights into the relevant section of the code, which would help save time in pinpointing the cause.

If I find additional details, I will update this issue accordingly.

Thank you in advance!

Best regards, Syméon

Symeon94 avatar May 21 '25 10:05 Symeon94

Minor addition/correction: The behavior matches my description for the initial press of Enter, but for subsequent presses, it sometimes retains the content at the top and other times scrolls. I've tested this multiple times, and it appears to behave differently with each attempt.

Symeon94 avatar May 21 '25 11:05 Symeon94

I believe I’ve identified the location of the problem, but I’m still investigating the root cause.

From my observations, this seems to originate from the Flowless library, so it may be an issue for a different repository. However, I’m documenting it here for reference.

Debugging Observations

  • When pressing enter for the first time (which causes the scroll), I see the variable firstVisibleIndex from Navigator set to 1.
  • Subsequent enter keys (which do not cause the scroll), the variable is set to 0.
  • Reviewing the code, the scrolling behavior appears to be occurring within Navigator::cropToNeighborhoodOf.
  • The firstVisibleIndex is updated by Navigator::fillViewportFrom, but it’s unclear what specifically causes it to be set to 1 when typing enter at the first position. When I debugged and clicked at the top, I saw it set to 0. But I could not debug while pressing enter because I lost focus because of my debugging tool. So, something in between clicking and pressing enter is setting it to 1.

Symeon94 avatar May 21 '25 12:05 Symeon94

The problem seems to be with ground being set to 1 in fillViewportFrom:

private void fillViewportFrom(int itemIndex) {
    int ground = fillTowardsGroundFrom0(itemIndex); // Set to 1 (itemIndex is the selected line after pressing enter 1,2,3,...)
    //…
    int first = Math.min(ground, sky);
    // ...
    firstVisibleIndex = first; // Should be 0, but it is 1 for itemIndex == 1
    lastVisibleIndex = last;
    positioner.cropTo(first, last + 1);
}

This comes from the following method which will receive as argument (1, 0.0) and output 1 for first line and (2, 0.0) for second and output 0.

It is not clear why the first case return 1 (and I have the impression it is being called multiple times).

int fillBackwardFrom0(int itemIndex, double upTo) {
    double min = orientation.minY(positioner.getVisibleCell(itemIndex));
    int i = itemIndex;
    while(min > upTo && i > 0) {
        --i;
        C c = positioner.placeEndFromStart(i, min);
        min = orientation.minY(c);
    }
    return i;
}

Symeon94 avatar May 21 '25 14:05 Symeon94