mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 19:01:25 +00:00
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 19c18977e0
Co-authored-by: robbyczgw-cla <239660374+robbyczgw-cla@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
This commit is contained in:
@@ -38,6 +38,16 @@ describe("SearchableSelectList", () => {
|
||||
expect(output[0]).toContain("search");
|
||||
});
|
||||
|
||||
it("does not truncate long labels on wide terminals when description is present", () => {
|
||||
const tail = "__TAIL__";
|
||||
const longLabel = `session-${"x".repeat(40)}${tail}`; // > 30 chars; tail would be lost before PR
|
||||
const items = [{ value: longLabel, label: longLabel, description: "desc" }];
|
||||
const list = new SearchableSelectList(items, 5, mockTheme);
|
||||
|
||||
const output = list.render(120).join("\n");
|
||||
expect(output).toContain(tail);
|
||||
});
|
||||
|
||||
it("filters items when typing", () => {
|
||||
const list = new SearchableSelectList(testItems, 5, mockTheme);
|
||||
|
||||
|
||||
@@ -219,20 +219,28 @@ export class SearchableSelectList implements Component {
|
||||
const displayValue = this.getItemLabel(item);
|
||||
|
||||
if (item.description && width > 40) {
|
||||
const maxValueWidth = Math.min(30, width - prefixWidth - 4);
|
||||
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
||||
const valueText = this.highlightMatch(truncatedValue, query);
|
||||
const spacingWidth = Math.max(1, 32 - visibleWidth(valueText));
|
||||
const spacing = " ".repeat(spacingWidth);
|
||||
const descriptionStart = prefixWidth + visibleWidth(valueText) + spacing.length;
|
||||
const remainingWidth = width - descriptionStart - 2;
|
||||
if (remainingWidth > 10) {
|
||||
const truncatedDesc = truncateToWidth(item.description, remainingWidth, "");
|
||||
// Highlight plain text first, then apply theme styling to avoid corrupting ANSI codes
|
||||
const highlightedDesc = this.highlightMatch(truncatedDesc, query);
|
||||
const descText = isSelected ? highlightedDesc : this.theme.description(highlightedDesc);
|
||||
const line = `${prefix}${valueText}${spacing}${descText}`;
|
||||
return isSelected ? this.theme.selectedText(line) : line;
|
||||
const minDescriptionWidth = 12;
|
||||
const spacingWidth = 2;
|
||||
const availableWidth = Math.max(1, width - prefixWidth - 2);
|
||||
|
||||
if (availableWidth > minDescriptionWidth + spacingWidth + 1) {
|
||||
const maxValueWidth = availableWidth - minDescriptionWidth - spacingWidth;
|
||||
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
||||
const valueText = this.highlightMatch(truncatedValue, query);
|
||||
|
||||
const usedByValue = visibleWidth(valueText);
|
||||
const remainingWidth = availableWidth - usedByValue;
|
||||
|
||||
if (remainingWidth > spacingWidth + 1) {
|
||||
const descriptionWidth = remainingWidth - spacingWidth;
|
||||
const spacing = " ".repeat(spacingWidth);
|
||||
const truncatedDesc = truncateToWidth(item.description, descriptionWidth, "");
|
||||
// Highlight plain text first, then apply theme styling to avoid corrupting ANSI codes
|
||||
const highlightedDesc = this.highlightMatch(truncatedDesc, query);
|
||||
const descText = isSelected ? highlightedDesc : this.theme.description(highlightedDesc);
|
||||
const line = `${prefix}${valueText}${spacing}${descText}`;
|
||||
return isSelected ? this.theme.selectedText(line) : line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user