description box: right border is offset for CJK / wide characters (padded by code units, not display width)

Author: NoirVoiderCreated Sep 15, 2026Updated Sep 15, 2026

Describe the bug

The suggestion description box (the right-hand box) is padded with String.prototype.padEnd, which counts UTF-16 code units, while renderBox() draws the border assuming the row occupies exactly width terminal columns. Whenever a description contains characters whose display width differs from their code-unit length — CJK text, BMP-wide emoji (e.g. U+2B50), ZWJ emoji sequences — the right border is offset: pushed out for wide characters, pulled in for ZWJ sequences.

The suggestion name box is unaffected, because truncateText() already pads with wcPadEnd()/wcswidth().

To Reproduce

  1. Add a local spec via specs.path:

~/.config/inshellisense/rc.toml

toml
[specs]
path = ["/Users/<you>/.config/inshellisense/specs"]

~/.config/inshellisense/specs/index.js

javascript
const specs = ["opencode"];
const diffVersionedCompletions = [];
export { specs as default, diffVersionedCompletions };

~/.config/inshellisense/specs/opencode.js

javascript
export default {
  name: "opencode",
  description: "OpenCode command line interface",
  subcommands: [
    { name: ["upgrade", "update"], description: "⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐" },
    { name: "auth", description: "以一条消息运行 OpenCode" },
  ],
};
  1. Start is and type opencode up

Actual behaviour

The description box's right border does not line up with the top border. With 10 × U+2B50 the row is padded to 38 columns instead of 28:

wide characters break the description box right border

Expected behaviour

Every row is padded to width display columns, so the box borders stay aligned, exactly like the name box.

Root cause

src/ui/utils.ts:37

typescript
return truncatedLines.map((line) => line.padEnd(width));

padEnd pads to width code units, but renderBox() (line 15) emits "│" + row + "│" assuming row is width columns wide. Measured with the repo's own wcswidth() (width = 28, i.e. descriptionWidth - borderWidth):

sample code units display cells padEnd → cells wcPadEnd → cells
Run OpenCode with a message 27 27 28 ✓ 28 ✓
以一条消息运行 OpenCode 16 23 35 28 ✓
⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ (U+2B50) 10 20 38 28 ✓
`` (U+1F680) 16 16 28 ✓ (coincidence) 28 ✓
‍‍‍‍‍‍ 24 18 22 28 ✓

Note that astral emoji happen to match (2 code units = 2 columns), which is why the bug can look like it only affects CJK; ZWJ sequences fail in the opposite direction.

Suggested fix

Use the display-width helper that already exists in the same file and is already used by truncateText():

typescript
return truncatedLines.map((line) => wcPadEnd(line, width));

ASCII descriptions are unaffected (wcswidth(text) === text.length for them). PR to follow.

Environment

  • inshellisense 0.0.4 (Homebrew), is --version0.0.4
  • macOS 27.0 (26A428)
  • zsh
  • VS Code integrated terminal

Related: #175, #302