Skip to content

fix(tree): remove incorrect start/end swap in Offset#704

Closed
xbrxr03 wants to merge 1 commit into
charmbracelet:mainfrom
xbrxr03:fix/tree-offset-swap
Closed

fix(tree): remove incorrect start/end swap in Offset#704
xbrxr03 wants to merge 1 commit into
charmbracelet:mainfrom
xbrxr03:fix/tree-offset-swap

Conversation

@xbrxr03

@xbrxr03 xbrxr03 commented Jun 22, 2026

Copy link
Copy Markdown

Problem

Tree.Offset(start, end) incorrectly swaps start and end when start > end. This makes Offset(2, 1) behave like Offset(1, 2), hiding rows from the wrong end of the tree.

Reported in #535 — calling Offset(2, 1) on [Duck, Duck, Goose, Duck, Duck] should skip 2 from the start and 1 from the end, but the swap inverts the meaning so you end up skipping 1 from the start and 2 from the end instead.

Fix

  • Removed the start/end swap in Offset(). The parameters now mean what they say: start = rows to skip from the beginning, end = rows to skip from the end. No magic reordering.
  • Added bounds clamping in Children() so out-of-range offsets produce empty results instead of panicking on negative loop bounds.
  • Negative values are clamped to zero in Offset().
  • Improved doc comment on Offset() to explain what the parameters actually do.

Comparison with #612

This PR builds on the same core insight as #612 (remove the swap), but goes further:

  1. Bounds safety: The existing Children() method could produce negative loop bounds if offset[1] > children.Length(). This PR adds explicit clamping so the iteration is always safe.
  2. Better negative handling: Old code treated negative end as "use children length" — this treated Offset(0, -1) as "show everything". The new behavior treats all negative values as zero, which is more intuitive.
  3. Comprehensive tests: 9 test cases covering zero offset, skip from start, skip from end, skip from both, start > end (the core bug), offset larger than children, negative values, offset that swallows all items, and equal offsets.

Test Results

=== RUN   TestTreeOffset
--- PASS: TestTreeOffset (0.00s)
    --- PASS: zero_offset
    --- PASS: skip_from_start
    --- PASS: skip_from_end
    --- PASS: skip_from_both
    --- PASS: start_greater_than_end
    --- PASS: offset_larger_than_children
    --- PASS: negative_values_clamped_to_zero
    --- PASS: offset_swallows_all
    --- PASS: equal_offset

Full suite passes: ok charm.land/lipgloss/v2/tree 0.216s

Closes #535

…ping

The Offset method incorrectly swapped start and end when start > end.
This made Offset(2, 1) behave like Offset(1, 2), hiding rows from
the wrong end of the tree. The original issue (charmbracelet#535) demonstrates:
Offset(2, 1) on [Duck, Duck, Goose, Duck, Duck] should skip 2 from
the start and 1 from the end, but the swap inverted the meaning.

The fix removes the swap entirely and adds proper bounds clamping in
Children() so that out-of-range offsets produce empty results instead
of panics. Negative values in Offset() are now clamped to zero.

Includes 9 test cases covering: zero offset, skip from start, skip from
end, skip from both, start > end (no swap), offset larger than children,
negative values, offset that swallows all items, and equal offset.

Closes charmbracelet#535
@xbrxr03

xbrxr03 commented Jun 29, 2026

Copy link
Copy Markdown
Author

Closing this PR due to lack of maintainer engagement. I'm happy to reopen if there's interest. Thanks for the great project.

@xbrxr03 xbrxr03 closed this Jun 29, 2026
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.

Tree Offset logic is broken

2 participants