Skip to content

fix(terminal): fallback to ASCII borders on legacy Windows consoles#41015

Closed
X-AlexBin wants to merge 1 commit intoopenclaw:mainfrom
X-AlexBin:fix/40853-win-console-unicode-table
Closed

fix(terminal): fallback to ASCII borders on legacy Windows consoles#41015
X-AlexBin wants to merge 1 commit intoopenclaw:mainfrom
X-AlexBin:fix/40853-win-console-unicode-table

Conversation

@X-AlexBin
Copy link
Copy Markdown

Summary

Fixes garbled Unicode table borders for commands like openclaw skills list on Windows PowerShell/CMD with default GBK (936) code page by automatically falling back to ASCII borders on legacy consoles.

Change Type

  • Bug fix

Scope

  • CLI / Terminal output

Linked Issue

Details

  • Introduce resolveDefaultBorder(platform, env) in src/terminal/table.ts to pick a safe default border style.
  • On non-Windows platforms, keep using Unicode borders by default.
  • On win32, use heuristics to detect modern terminals (Windows Terminal, VS Code, xterm-like) and keep Unicode there, otherwise default to ASCII (+-|) to avoid mojibake on GBK consoles.
  • Keep opts.border fully honored so callers can still explicitly choose "unicode" | "ascii" | "none".

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 9, 2026

Greptile Summary

This PR adds a resolveDefaultBorder heuristic to src/terminal/table.ts that automatically falls back from Unicode box-drawing characters to plain ASCII (+-|) on legacy Windows consoles (GBK / code-page 936), fixing mojibake reported in #40853. Non-Windows platforms are unaffected.

Key findings:

  • Test breakage on Windows dev machines (logic issue): Four existing tests (prefers shrinking flex columns, expands flex columns, wraps ANSI-colored cells, resets ANSI styling) assert the Unicode character without explicitly setting border: "unicode". Before this PR the default was always "unicode"; now it is environment-dependent. On any Windows machine where none of WT_SESSION, an xterm/cygwin/msys TERM, or TERM_PROGRAM=vscode is present the tests will fail. Each affected test should pass border: "unicode" explicitly.

  • Missing terminal coverage (style suggestion): ConEmu / Cmder (sets ConEmuANSI=ON) and terminals advertising COLORTERM=truecolor are not detected, so their users will silently receive ASCII borders even though they support Unicode. The scope is documented in the PR description but worth noting in a comment or extending if those user populations are significant.

  • No unit tests for resolveDefaultBorder: The new detection function has no dedicated tests. Given that the entire fix hinges on it, a small suite of parameterised tests for the Win32 heuristics would substantially increase confidence.

Confidence Score: 3/5

  • Safe to merge on Linux/macOS CI, but existing tests will break when run on a Windows machine without modern-terminal env vars set.
  • The fix itself is logically sound and correctly guarded behind a win32 platform check. However, it silently changes the default border style at runtime, which breaks the existing test suite on Windows environments that don't match the modern-terminal heuristics. This is a concrete, reproducible failure that needs to be addressed before the PR can be considered fully correct.
  • src/terminal/table.ts and its companion test file src/terminal/table.test.ts both need attention — the test assertions must be updated to explicitly pass border: "unicode" so they remain deterministic across platforms.

Last reviewed commit: 3fbfcaa

Comment on lines +34 to +41
const isModernTerminal =
!!env.WT_SESSION ||
term.includes("xterm") ||
term.includes("cygwin") ||
term.includes("msys") ||
termProgram === "vscode";

return isModernTerminal ? "unicode" : "ascii";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing COLORTERM and ConEmu heuristics

The detection currently covers Windows Terminal (WT_SESSION), xterm-like shells, Cygwin, MSYS2, and VS Code — but misses a couple of widely-used Windows terminals that support Unicode:

  • ConEmu / Cmder sets ConEmuANSI=ON (or CMDER_ROOT) but does not set WT_SESSION or a TERM value that contains "xterm". Without this check, ConEmu users would silently fall back to ASCII.
  • COLORTERM=truecolor (or 24bit) is a well-established signal for full-colour / modern terminal support and is set by many terminals that do support Unicode box-drawing characters.

Neither omission causes a crash, and the fallback to ASCII is safe. However, it is worth documenting the intentional scope limitation (or extending the checks) so that ConEmu users aren't caught off guard.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/terminal/table.ts
Line: 34-41

Comment:
**Missing `COLORTERM` and ConEmu heuristics**

The detection currently covers Windows Terminal (`WT_SESSION`), xterm-like shells, Cygwin, MSYS2, and VS Code — but misses a couple of widely-used Windows terminals that support Unicode:

- **ConEmu / Cmder** sets `ConEmuANSI=ON` (or `CMDER_ROOT`) but does not set `WT_SESSION` or a `TERM` value that contains "xterm". Without this check, ConEmu users would silently fall back to ASCII.
- **`COLORTERM=truecolor`** (or `24bit`) is a well-established signal for full-colour / modern terminal support and is set by many terminals that do support Unicode box-drawing characters.

Neither omission causes a crash, and the fallback to ASCII is safe. However, it is worth documenting the intentional scope limitation (or extending the checks) so that ConEmu users aren't caught off guard.

How can I resolve this? If you propose a fix, please make it concise.

return next;
});
const border = opts.border ?? "unicode";
const border = opts.border ?? resolveDefaultBorder(process.platform, process.env);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing tests will fail on Windows without a modern terminal

Several tests in src/terminal/table.test.ts assert against the Unicode vertical-bar character (U+2502) without explicitly setting border: "unicode":

// table.test.ts:18
expect(out).toMatch(/│ Dashboard\s+│/);

// table.test.ts:80-81
const lastSep = line.lastIndexOf("│");
expect(lastSep).toBeGreaterThan(resetIndex);

Before this PR, border always defaulted to "unicode", so those assertions were always safe. After this change, the default is determined at runtime by resolveDefaultBorder(process.platform, process.env). On a Windows machine where none of WT_SESSION, xterm/cygwin/msys in TERM, or TERM_PROGRAM=vscode is set, the function returns "ascii" and every test that hardcodes will fail.

The simplest fix is to pin border: "unicode" in the tests that care about the specific character used:

// table.test.ts – prefers shrinking flex columns
const out = renderTable({
  border: "unicode",
  // ...
});

Doing this for the four affected tests (prefers shrinking flex columns, expands flex columns, wraps ANSI-colored cells, resets ANSI styling) ensures they remain deterministic regardless of the host environment.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/terminal/table.ts
Line: 263

Comment:
**Existing tests will fail on Windows without a modern terminal**

Several tests in `src/terminal/table.test.ts` assert against the Unicode vertical-bar character `` (U+2502) without explicitly setting `border: "unicode"`:

```
// table.test.ts:18
expect(out).toMatch(/│ Dashboard\s+│/);

// table.test.ts:80-81
const lastSep = line.lastIndexOf("│");
expect(lastSep).toBeGreaterThan(resetIndex);
```

Before this PR, `border` always defaulted to `"unicode"`, so those assertions were always safe. After this change, the default is determined at runtime by `resolveDefaultBorder(process.platform, process.env)`. On a Windows machine where none of `WT_SESSION`, `xterm`/`cygwin`/`msys` in `TERM`, or `TERM_PROGRAM=vscode` is set, the function returns `"ascii"` and every test that hardcodes `` will fail.

The simplest fix is to pin `border: "unicode"` in the tests that care about the specific character used:

```ts
// table.test.ts – prefers shrinking flex columns
const out = renderTable({
  border: "unicode",
  // ...
});
```

Doing this for the four affected tests (`prefers shrinking flex columns`, `expands flex columns`, `wraps ANSI-colored cells`, `resets ANSI styling`) ensures they remain deterministic regardless of the host environment.

How can I resolve this? If you propose a fix, please make it concise.

@easyteacher
Copy link
Copy Markdown

Should it also check the current code page?

@vincentkoc
Copy link
Copy Markdown
Member

Canonical follow-up is now #43520.

I kept that PR focused to the legacy-Windows table-border fallback and added explicit regression coverage for legacy vs. modern Windows terminal defaults.

@vincentkoc
Copy link
Copy Markdown
Member

Fix #43520

@vincentkoc vincentkoc closed this Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Chinease 文字乱码 character messing

4 participants