Skip to content

don't rebuild VF#430

Open
johanvos wants to merge 10 commits intogluonhq:mainfrom
johanvos:429-novfrebuild
Open

don't rebuild VF#430
johanvos wants to merge 10 commits intogluonhq:mainfrom
johanvos:429-novfrebuild

Conversation

@johanvos
Copy link
Contributor

Do not rebuild the VF on every change in the backing TextBuffer.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the text rendering performance by replacing the refreshTextFlow() call with a new, more lightweight textBufferChanged() method in response to TextBuffer events. The goal is to avoid rebuilding the entire text flow (VF) on every change in the backing TextBuffer.

Key changes:

  • Modified the textChangeListener to call textBufferChanged(e) instead of refreshTextFlow()
  • Added a new textBufferChanged() method that performs minimal operations: resetting nonTextNodes counter, resetting the character iterator, and conditionally requesting layout only when the number of non-text nodes changes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

nonTextNodes.set(0);
viewModel.resetCharacterIterator();
if (nonTextNodesCount != nonTextNodes.get()) {
// when number of images changes, caret
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The comment is incomplete and unclear. It starts with "when number of images changes, caret" but doesn't finish the thought. Consider completing this comment to explain what happens to the caret when the number of images changes.

Copilot uses AI. Check for mistakes.
Comment on lines +838 to +843
nonTextNodes.set(0);
viewModel.resetCharacterIterator();
if (nonTextNodesCount != nonTextNodes.get()) {
// when number of images changes, caret
requestLayout();
nonTextNodesCount = nonTextNodes.get();
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The new textBufferChanged method is missing several important operations that were present in refreshTextFlow:

  1. paragraphListView.updateLayout() - which ensures decoration changes are applied
  2. getSkinnable().requestFocus() - which requests focus on the component
  3. The objectsCacheEvictionTimer pause/start logic for managing cache eviction

Without these, text buffer changes may not properly update the UI (decoration changes won't be applied), focus behavior may be incorrect, and the cache eviction timer won't be properly managed. Consider whether these operations are intentionally omitted or if they should be included in this method.

Suggested change
nonTextNodes.set(0);
viewModel.resetCharacterIterator();
if (nonTextNodesCount != nonTextNodes.get()) {
// when number of images changes, caret
requestLayout();
nonTextNodesCount = nonTextNodes.get();
objectsCacheEvictionTimer.pause();
try {
nonTextNodes.set(0);
viewModel.resetCharacterIterator();
// this ensures changes in decoration are applied:
paragraphListView.updateLayout();
computeFullHeight();
if (nonTextNodesCount != nonTextNodes.get()) {
// when number of images changes, caret
requestLayout();
nonTextNodesCount = nonTextNodes.get();
}
getSkinnable().requestFocus();
} finally {
objectsCacheEvictionTimer.start();

Copilot uses AI. Check for mistakes.
Comment on lines +837 to +845
private void textBufferChanged(TextBuffer.Event e) {
nonTextNodes.set(0);
viewModel.resetCharacterIterator();
if (nonTextNodesCount != nonTextNodes.get()) {
// when number of images changes, caret
requestLayout();
nonTextNodesCount = nonTextNodes.get();
}
}
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The Event parameter 'e' is not used in this method, but there are different event types (InsertEvent, DeleteEvent, DecorateEvent) available in TextBuffer.Event. Consider using the event type to determine whether certain operations are needed. For example, DecorateEvent might specifically require paragraphListView.updateLayout() to ensure decoration changes are applied, while InsertEvent and DeleteEvent might not.

Copilot uses AI. Check for mistakes.
private final SmartTimer objectsCacheEvictionTimer;

private final Consumer<TextBuffer.Event> textChangeListener = e -> refreshTextFlow();
private final Consumer<TextBuffer.Event> textChangeListener = e -> textBufferChanged(e);
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The lambda expression can be simplified to a method reference for better readability.

Suggested change
private final Consumer<TextBuffer.Event> textChangeListener = e -> textBufferChanged(e);
private final Consumer<TextBuffer.Event> textChangeListener = this::textBufferChanged;

Copilot uses AI. Check for mistakes.
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.

1 participant