-
-
Notifications
You must be signed in to change notification settings - Fork 207
fix(prompts): truncate wide-character box titles by display width #578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@clack/prompts": patch | ||
| --- | ||
|
|
||
| Fix `box()` so a title wider than the box is truncated by display width instead of UTF-16 code units. A wide-character (CJK) title that overflowed the title budget previously produced ragged borders, and could throw `RangeError: Invalid count value` once the remainder passed to `'─'.repeat(...)` went negative. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -96,6 +96,22 @@ function getPaddingForLine( | |||||||||||||||||||||
| return [leftPadding, rightPadding]; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| function truncateToWidth(str: string, maxWidth: number): string { | ||||||||||||||||||||||
| const ellipsis = '...'; | ||||||||||||||||||||||
| const target = maxWidth - stringWidth(ellipsis); | ||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||||||||||||||||||||||
| let result = ''; | ||||||||||||||||||||||
| let width = 0; | ||||||||||||||||||||||
| for (const char of str) { | ||||||||||||||||||||||
| const charWidth = stringWidth(char); | ||||||||||||||||||||||
| if (width + charWidth > target) { | ||||||||||||||||||||||
| break; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| result += char; | ||||||||||||||||||||||
| width += charWidth; | ||||||||||||||||||||||
|
Comment on lines
+106
to
+110
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
to avoid computing it twice |
||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return result + ellipsis; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const defaultFormatBorder = (text: string) => text; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
|
|
@@ -162,7 +178,7 @@ export const box = (message = '', title = '', opts?: BoxOptions) => { | |||||||||||||||||||||
| const innerWidth = boxWidth - borderTotalWidth; | ||||||||||||||||||||||
| const maxTitleLength = innerWidth - titlePadding * 2; | ||||||||||||||||||||||
| const truncatedTitle = | ||||||||||||||||||||||
| titleWidth > maxTitleLength ? `${title.slice(0, maxTitleLength - 3)}...` : title; | ||||||||||||||||||||||
| titleWidth > maxTitleLength ? truncateToWidth(title, maxTitleLength) : title; | ||||||||||||||||||||||
| const [titlePaddingLeft, titlePaddingRight] = getPaddingForLine( | ||||||||||||||||||||||
| stringWidth(truncatedTitle), | ||||||||||||||||||||||
| innerWidth, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should really be in
common.tssince it will be useful in other places too