Skip to content

fix(tui): keep truncateMiddle within maxLength when maxLength is 1 or 2#37460

Open
VINODvoid wants to merge 1 commit into
anomalyco:devfrom
VINODvoid:fix/truncate-middle-small-maxlength
Open

fix(tui): keep truncateMiddle within maxLength when maxLength is 1 or 2#37460
VINODvoid wants to merge 1 commit into
anomalyco:devfrom
VINODvoid:fix/truncate-middle-small-maxlength

Conversation

@VINODvoid

@VINODvoid VINODvoid commented Jul 17, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #37458

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

truncateMiddle hands back a string longer than maxLength when maxLength is 1 or 2:

truncateMiddle("abcdefghij", 1) -> "…abcdefghij"
truncateMiddle("abcdefghij", 2) -> "a…abcdefghij"

The last line is str.slice(0, keepStart) + ellipsis + str.slice(-keepEnd). keepEnd comes out as 0 for those two cases, and slice(-0) is just slice(0) in JS, so you get the whole string back where an empty tail was meant to go.

Swapped it for str.slice(str.length - keepEnd), which is slice(str.length) -> "" when keepEnd is 0. For anything >= 1 the two are the same expression, so maxLength >= 3 doesn't move.

I ran into this from dialog-select.tsx:701:

Locale.truncateMiddle(detail, Math.max(1, Math.min(76, dimensions().width - 12)))

The Math.max(1, ...) is there to keep the width sane on small terminals, except 1 is the value that breaks. So under ~15 columns the detail line printed in full and ran past the dialog. splash.ts:203 does the same Math.max(1, ...) thing.

#37369 fixes the identical -0 slip in truncateLeft. This is the sibling it doesn't touch.

How did you verify your code works?

Added packages/tui/test/util/locale.test.ts. Put the old line back and 2 of the 4 fail:

✗ handles a maxLength too small to keep any trailing characters
  Expected: "…"
  Received: "…abcdefghij"

With the fix, 4 pass.

Diffed old vs new across maxLength 1..12 on a 10-char string. Only 1 and 2 move:

1  "…abcdefghij"  -> "…"
2  "a…abcdefghij" -> "a…"
3  "a…j"          -> "a…j"
5  "ab…ij"        -> "ab…ij"

Also ran the dialog-select.tsx:701 expression itself at widths 10-20. Widths 13 and 14 gave back 40 and 41 chars before, correct output after.

packages/tui: 195 pass, 0 fail. Pre-push typecheck: 30/30 packages.

Screenshots / recordings

Nothing to show really — text that should have been truncated now is.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

keepEnd is 0 when maxLength <= 2, and str.slice(-0) returns the whole
string rather than an empty tail, so truncateMiddle returned its input with an
ellipsis attached instead of truncating. Use a positive index so the empty tail
is actually empty. Behavior is unchanged for maxLength >= 3.

Reachable from dialog-select.tsx:701, where Math.max(1, ...) clamps to exactly
the broken value on terminals narrower than ~15 columns.
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Potential Duplicate Found:

This previous PR seems to have tackled the same bug. You should verify whether PR #34482 was already merged or closed, and if it was merged, PR #37460 may be redundant.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.

truncateMiddle returns a string longer than maxLength when maxLength is 1 or 2

1 participant