Skip to content

truncateMiddle overflows when the width is 1 or 2 #59912

Closed

Description

@Eapp1e

Describe the bug

truncateMiddle returns a string longer than the requested width when the width is 1 or 2.

Both copies behave this way: packages/util/src/path.ts and packages/tui/src/util/locale.ts.

Steps to reproduce

truncateMiddle("abcdefghij", 1) // "…abcdefghij" (11 characters)
truncateMiddle("abcdefghij", 2) // "a…abcdefghij" (12 characters)

For width 4 and above the result fits ("ab…j", "abcd…ghij").

Cause

keepEnd = Math.floor((maxLength - 1) / 2) is 0 for widths 1 and 2, and str.slice(-0) is str.slice(0), i.e. the whole string.

Real call site

packages/tui/src/ui/dialog-select.tsx:987 passes Math.max(1, props.width) to Locale.truncateMiddle, so a narrow dialog renders a line wider than the pane.

Expected

The result should never be wider than maxLength: width 1 should give "…", width 2 "a…".

Activity

  1. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the clear report. I reproduced this on the latest dev (3d7eceb): with "abcdefghij", both truncateMiddle in packages/util/src/path.ts and Locale.truncateMiddle in packages/tui/src/util/locale.ts return "…abcdefghij" for width 1 and "a…abcdefghij" for width 2. Widths 3 and up fit. In v2.2.0 both functions have the same code. The script below calls both copies and exits with status 1 when a result is longer than the requested width.

    Related: earlier reports of the same slice(-0) problem (#37458, #34395, #20880, #41054) were closed without a fix. Open PR #55953 fixes the packages/util copy but not the TUI one.

    Reproduction script (repro.ts)
    // Usage: bun repro.ts [path-to-opencode-checkout]   (default /workspace/repo)
    const root = process.argv[2] ?? "/workspace/repo"
    const util = await import(`${root}/packages/util/src/path.ts`)
    const locale = await import(`${root}/packages/tui/src/util/locale.ts`)
    let failed = false
    for (const [name, fn] of [["util truncateMiddle", util.truncateMiddle], ["tui Locale.truncateMiddle", locale.truncateMiddle]] as const) {
      for (const w of [1, 2, 3, 4, 9]) {
        const out = fn("abcdefghij", w)
        const ok = out.length <= w
        if (!ok) failed = true
        console.log(`${name}("abcdefghij", ${w}) = ${JSON.stringify(out)} (length ${out.length}) ${ok ? "OK" : "OVERFLOW"}`)
      }
    }
    process.exit(failed ? 1 : 0)

    Run it: bun repro.ts

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions