Skip to content

Sidebar: layoutFor counts open recent projects as rendered rows, corrupting section height, scroll clamp, and hit testing #428

Description

@coneilen

Summary

Sidebar.layoutFor() counts every entry in model.recent_projects as a rendered 24px project row, but appendRows() skips rendering any recent project that is already open. Whenever an open project also appears in recent_projects, the layout/scroll math disagrees with the rows actually drawn.

Found by wiring Sidebar.zig's previously-unexecuted tests into CI under #424. These are pre-existing failures that had never run, not regressions.

Evidence (verified on main)

The row producer skips open projects:

Sidebar.zig:507   if (project.isRemote() or isProjectOpen(model, project.path)) continue;
Sidebar.zig:518   if (!project.isRemote() or isProjectOpen(model, project.path)) continue;

The layout consumer does not:

Sidebar.zig:588   .project_count = model.recent_projects.items.len,

and that count drives geometry directly:

Sidebar.zig:485   return @as(i32, @intCast((self.project_count + self.project_heading_count) * 24));

So project_count overcounts by exactly the number of recent projects that are currently open. Section height, every offset derived from it, and scroll clamping are all inflated.

Note :647 and :652 (projectHeadingCount helpers) do apply !isProjectOpen(...), so heading visibility already respects the skip. Only the row count does not, which is why this reads as an oversight rather than an intentional model.

Observed failures

Three tests in Sidebar.zig fail on first execution:

test result
shared sidebar layout routes every loop row after project rows and scroll expected 0, found 1
sidebar scroll clamps overflow, shrink, and resize expected 334, found 410
recent project rows exclude folders already open in the projects list expected .open_project, found .quick_chat_overview

The 334 vs 410 delta is 76px, and the third failure shows hit-testing resolving to the wrong row kind - a click lands on a different row than the one drawn. These are consistent with an overcounted project section, not with three unrelated defects.

App.zig imports Sidebar.zig, so the same three failures surface in the App test binary too.

User-visible impact

With at least one open project also present in recents: the sidebar reserves vertical space for rows that are never drawn, sections below the project list sit lower than the content they label, scroll range over-extends past the last real row, and hit testing can resolve to the wrong row. The third failing test indicates a click intended for a project row can be attributed to a different row kind entirely.

Expected

layoutFor() counts only rows appendRows() will actually render - i.e. apply the same isProjectOpen (and remote/local partition) filtering used at :507/:518, consistent with how :647/:652 already work.

Fix guidance

The three failing tests encode the correct expectations; make them pass rather than adjusting them. Deriving the count from the same predicate used by appendRows (rather than duplicating the condition) would prevent the two from drifting apart again.

Sidebar.zig has 22 tests total and is being wired into the harness by #426, which quarantines these three rather than silently deleting them. Once fixed, remove the quarantine so all 22 gate normally.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions