Skip to content

Large blank space periodically appearing when scrolling in the editor #1346

Closed

Description

@Ben-ADFA

Ref. 4171

Please see the attached video showing the behavior.

From Andrian (@Andrian_MD) on Telegram:
https://t.me/CodeOnTheGoDiscussions/5352
"no text flickering and search is back but that empty space now is the problem"

User specs:
Samsung A71, Android 13

Video:
https://github.com/user-attachments/assets/84465570-f2c4-4a17-a167-47da4e112ea9

Also reported by DePyraxe Jr (@Depyraxe):
https://t.me/CodeOnTheGoDiscussions/5410

User specs:
infinix hot 30i 8ram, Android 12

Another report:
https://t.me/CodeOnTheGoDiscussions/5412
Image

Activity

  1. coderabbitai commented on May 27, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #1313 - ADFA-3987 | Fix persistent space obscuring Find in File dialog [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. self-assigned this
    on May 28, 2026
  3. coderabbitai commented on May 28, 2026

    @coderabbitai
    Contributor

    Coding Plan

    Summary

    • Eliminate the root cause by guarding setTextSize() to skip redundant calls when the editor already has the target size
    • Add defensive postInvalidate() calls after layout-affecting preference changes as a safety net
    • Reorder content initialization to apply display preferences before setting content, reducing layout recalculation overhead
    • All changes are localized to CodeEditorView.kt and follow existing patterns in the codebase
    Design Choices
    Design Choice 1: The blank space issue is caused by redundant layout recalculations during zoom/scroll

    Options Considered:

    1. Fix the redundant setTextSize() call by adding a guard that checks if the new size matches the current editor size
    2. Add a zoom-in-progress flag that suppresses preference change handling during active zoom gestures
    3. Delay preference saving until zoom gesture completes

    Chosen Option: 1

    Rationale: Simplest solution that directly addresses the redundancy without introducing state management complexity. Checking current size before calling setTextSize() is defensive and handles all paths uniformly.

    💡 User Tips

    Regenerate the plan with different choices with @coderabbitai <feedback>.

    Implementation Steps

    Phase 1: Eliminate Redundant Font Size Updates

    This phase addresses the root cause—the double setTextSize() call during zoom operations. When the user pinch-zooms, sora-editor applies the new size internally before firing TextSizeChangeEvent. The current code then saves to preferences, which triggers onFontSizePrefChanged() to call setTextSize() again with the same value. This redundant call causes sora-editor to recalculate layout mid-gesture.

    Task 1: Add Size Comparison Guard in Font Size Preference Handler

    Prevent redundant setTextSize() calls by comparing the preference value against the editor's current text size before applying.

    • Modify onFontSizePrefChanged() in app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt
    • Before calling binding.editor.setTextSize(textSize), check if the editor's current text size (in SP) already matches the target size within a small tolerance (e.g., 0.01f)
    • If sizes match, skip the setTextSize() call entirely
    • This handles both the zoom path (where sora already applied the size) and the settings UI path (where the call is needed)
    Task 2: Add Size Comparison Guard in Ctrl+Scroll Zoom Handler

    Apply the same guard to the changeFontSizeBy() method which also triggers a redundant update.

    • Modify changeFontSizeBy() in app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt
    • After calling binding.editor.setTextSize(newSize), the preference assignment EditorPreferences.fontSize = newSize will trigger onFontSizePrefChanged()
    • With Task 1.1's guard in place, the redundant call will be automatically prevented
    • No additional changes needed here beyond ensuring the guard in Task 1.1 is robust
    🤖 Prompt for AI agents
    This phase eliminates the root cause of blank spaces during scrolling by
    preventing double `setTextSize()` calls during zoom operations. All changes are
    in `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt`.
    
    **Task 1: Guard in `onFontSizePrefChanged()`**
    - Locate `onFontSizePrefChanged()` in `CodeEditorView.kt`
    - Before calling `binding.editor.setTextSize(textSize)`, add a check that
    compares the incoming `textSize` against the editor's current text size (in SP)
    - Use a small float tolerance (e.g., 0.01f) for the comparison
    - If the sizes match within tolerance, skip the `setTextSize()` call entirely
    and return early
    - This guard handles both the pinch-zoom path (where sora-editor already applied
    the size before firing `TextSizeChangeEvent`) and the settings UI path (where
    the call is genuinely needed)
    
    **Task 2: Verify guard coverage for `changeFontSizeBy()`**
    - Locate `changeFontSizeBy()` in `CodeEditorView.kt`
    - After `binding.editor.setTextSize(newSize)` is called and
    `EditorPreferences.fontSize = newSize` triggers `onFontSizePrefChanged()`, the
    guard from Task 1 will automatically prevent the redundant second call
    - No additional code changes are required in `changeFontSizeBy()` itself; verify
    the guard in Task 1 is robust enough to cover this path
    

    Phase 2: Add Defensive Invalidation After Layout-Affecting Changes

    This phase adds explicit invalidation calls as a safety net. While sora-editor should handle invalidation internally, the exploration found no explicit invalidate() or requestLayout() calls in the AndroidIDE wrapper code. Adding defensive invalidation ensures proper redraw even if sora-editor's internal mechanisms are insufficient for certain state transitions.

    Task 1: Add Post-Invalidation to Font Size Change Handler

    Ensure the editor properly redraws after font size changes, particularly when the change comes from settings rather than zoom.

    • Modify onFontSizePrefChanged() in app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt
    • After calling setTextSize() (when it's actually called, not skipped), add a binding.editor.postInvalidate() call
    • This ensures a full redraw is scheduled after the layout recalculation completes
    Task 2: Add Post-Invalidation to Word Wrap Change Handler

    Ensure proper redraw after word wrap toggling, which significantly affects line layout and RenderNode caches.

    • Modify onWordwrapPrefChanged() in app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt
    • After setting binding.editor.isWordwrap = enabled, add a binding.editor.postInvalidate() call
    • This ensures stale per-line RenderNode display lists are refreshed after the wrap mode change
    🤖 Prompt for AI agents
    This phase adds defensive `postInvalidate()` calls as a safety net to ensure
    proper redraws after layout-affecting preference changes in
    `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt`.
    
    **Task 1: Post-invalidation in `onFontSizePrefChanged()`**
    - Locate `onFontSizePrefChanged()` in `CodeEditorView.kt`
    - After the `binding.editor.setTextSize(textSize)` call (i.e., only in the
    branch where the call is not skipped by the Phase 1 guard), add
    `binding.editor.postInvalidate()`
    - This schedules a full redraw after the layout recalculation triggered by the
    font size change completes
    
    **Task 2: Post-invalidation in `onWordwrapPrefChanged()`**
    - Locate `onWordwrapPrefChanged()` in `CodeEditorView.kt`
    - After the line `binding.editor.isWordwrap = enabled`, add
    `binding.editor.postInvalidate()`
    - This ensures stale per-line RenderNode display lists are refreshed after the
    wrap mode change
    

    Phase 3: Optimize Content Initialization Order

    This phase reorders preference application during file loading to reduce unnecessary layout recalculations. Currently, configureEditorIfNeeded() is called after setText(), meaning font size and word wrap are applied post-content-load, forcing a second full layout pass.

    Apply Display Preferences Before Setting Content

    Reorder initialization to apply display preferences before content is set, reducing layout churn.

    • Modify initializeContent() in app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt
    • Move the configureEditorIfNeeded() call (or at minimum, onFontSizePrefChanged() and onWordwrapPrefChanged()) to execute before ideEditor.setText(content, args)
    • This allows the editor to have correct font size and wrap mode before content triggers layout calculations
    • Ensure this change doesn't break any assumptions about editor state during language setup in postRead()
    🤖 Prompt for AI agents
    This phase reorders the content initialization sequence in
    `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt` to reduce
    unnecessary layout recalculations during file loading.
    
    **Task: Reorder calls in `initializeContent()`**
    - Locate `initializeContent()` in `CodeEditorView.kt`
    - Move the `configureEditorIfNeeded()` call (or at minimum the individual calls
    to `onFontSizePrefChanged()` and `onWordwrapPrefChanged()`) so they execute
    **before** the `ideEditor.setText(content, args)` call
    - This ensures the editor has the correct font size and word wrap mode before
    content is loaded, avoiding a second full layout pass after content is set
    - Verify that moving this call does not break any assumptions about editor state
    that `postRead()` depends on during language setup
    
    Research

    The editor is built on the sora-editor library (v0.23.6), wrapped by IDEEditor (a CodeEditor subclass) and managed by CodeEditorView. Font size changes flow through EditorPreferences which broadcasts PreferenceChangeEvent via EventBus. During pinch-zoom, sora-editor fires TextSizeChangeEvent after internally applying the new size, but the current implementation also saves to preferences—triggering a second setTextSize() call through the preference change listener. Neither IDEEditor nor CodeEditorView contain explicit invalidate() or requestLayout() calls after state changes; they rely entirely on sora-editor's internal invalidation mechanisms.


    🚀 Next Steps

    🤖 All AI agent prompts combined
    Task: 1
    
    This phase eliminates the root cause of blank spaces during scrolling by
    preventing double `setTextSize()` calls during zoom operations. All changes are
    in `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt`.
    
    **Task 1: Guard in `onFontSizePrefChanged()`**
    - Locate `onFontSizePrefChanged()` in `CodeEditorView.kt`
    - Before calling `binding.editor.setTextSize(textSize)`, add a check that
    compares the incoming `textSize` against the editor's current text size (in SP)
    - Use a small float tolerance (e.g., 0.01f) for the comparison
    - If the sizes match within tolerance, skip the `setTextSize()` call entirely
    and return early
    - This guard handles both the pinch-zoom path (where sora-editor already applied
    the size before firing `TextSizeChangeEvent`) and the settings UI path (where
    the call is genuinely needed)
    
    **Task 2: Verify guard coverage for `changeFontSizeBy()`**
    - Locate `changeFontSizeBy()` in `CodeEditorView.kt`
    - After `binding.editor.setTextSize(newSize)` is called and
    `EditorPreferences.fontSize = newSize` triggers `onFontSizePrefChanged()`, the
    guard from Task 1 will automatically prevent the redundant second call
    - No additional code changes are required in `changeFontSizeBy()` itself; verify
    the guard in Task 1 is robust enough to cover this path
    ===============================================================================
    
    Task: 2
    
    This phase adds defensive `postInvalidate()` calls as a safety net to ensure
    proper redraws after layout-affecting preference changes in
    `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt`.
    
    **Task 1: Post-invalidation in `onFontSizePrefChanged()`**
    - Locate `onFontSizePrefChanged()` in `CodeEditorView.kt`
    - After the `binding.editor.setTextSize(textSize)` call (i.e., only in the
    branch where the call is not skipped by the Phase 1 guard), add
    `binding.editor.postInvalidate()`
    - This schedules a full redraw after the layout recalculation triggered by the
    font size change completes
    
    **Task 2: Post-invalidation in `onWordwrapPrefChanged()`**
    - Locate `onWordwrapPrefChanged()` in `CodeEditorView.kt`
    - After the line `binding.editor.isWordwrap = enabled`, add
    `binding.editor.postInvalidate()`
    - This ensures stale per-line RenderNode display lists are refreshed after the
    wrap mode change
    ===============================================================================
    
    Task: 3
    
    This phase reorders the content initialization sequence in
    `app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt` to reduce
    unnecessary layout recalculations during file loading.
    
    **Task: Reorder calls in `initializeContent()`**
    - Locate `initializeContent()` in `CodeEditorView.kt`
    - Move the `configureEditorIfNeeded()` call (or at minimum the individual calls
    to `onFontSizePrefChanged()` and `onWordwrapPrefChanged()`) so they execute
    **before** the `ideEditor.setText(content, args)` call
    - This ensures the editor has the correct font size and word wrap mode before
    content is loaded, avoiding a second full layout pass after content is set
    - Verify that moving this call does not break any assumptions about editor state
    that `postRead()` depends on during language setup
    
    💡 Iterate on the plan with: `@coderabbitai` <feedback>
    Example Feedback
    - `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2.
    - `@coderabbitai` For design choice 1 go ahead with option 3 and replan.
    

    💬 Have feedback or questions? Drop into our discord!

  4. sb-codz commented on May 31, 2026

    @sb-codz

    On my case is
    This problem comes when i use system navigation button bar.
    And when i use gesture mode this space reduced.

    Now problem is there. In version(0530-1229) this is not public release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions