mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 12:11:24 +00:00
fix (tui): preserve copy-sensitive token wrapping
This commit is contained in:
@@ -160,4 +160,27 @@ describe("sanitizeRenderableText", () => {
|
||||
|
||||
expect(longestSegment).toBeLessThanOrEqual(32);
|
||||
});
|
||||
|
||||
it("preserves long filesystem paths verbatim for copy safety", () => {
|
||||
const input =
|
||||
"/Users/jasonshawn/PerfectXiao/a_very_long_directory_name_designed_specifically_to_test_the_line_wrapping_issue/file.txt";
|
||||
const sanitized = sanitizeRenderableText(input);
|
||||
|
||||
expect(sanitized).toBe(input);
|
||||
});
|
||||
|
||||
it("preserves long urls verbatim for copy safety", () => {
|
||||
const input =
|
||||
"https://example.com/this/is/a/very/long/url/segment/that/should/remain/contiguous/when/rendered";
|
||||
const sanitized = sanitizeRenderableText(input);
|
||||
|
||||
expect(sanitized).toBe(input);
|
||||
});
|
||||
|
||||
it("preserves long file-like underscore tokens for copy safety", () => {
|
||||
const input = "administrators_authorized_keys_with_extra_suffix".repeat(2);
|
||||
const sanitized = sanitizeRenderableText(input);
|
||||
|
||||
expect(sanitized).toBe(input);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,9 @@ const MAX_TOKEN_CHARS = 32;
|
||||
const LONG_TOKEN_RE = /\S{33,}/g;
|
||||
const LONG_TOKEN_TEST_RE = /\S{33,}/;
|
||||
const BINARY_LINE_REPLACEMENT_THRESHOLD = 12;
|
||||
const URL_PREFIX_RE = /^(https?:\/\/|file:\/\/)/i;
|
||||
const WINDOWS_DRIVE_RE = /^[a-zA-Z]:[\\/]/;
|
||||
const FILE_LIKE_RE = /^[a-zA-Z0-9._-]+$/;
|
||||
|
||||
function hasControlChars(text: string): boolean {
|
||||
for (const char of text) {
|
||||
@@ -47,6 +50,35 @@ function chunkToken(token: string, maxChars: number): string[] {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function isCopySensitiveToken(token: string): boolean {
|
||||
if (URL_PREFIX_RE.test(token)) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
token.startsWith("/") ||
|
||||
token.startsWith("~/") ||
|
||||
token.startsWith("./") ||
|
||||
token.startsWith("../")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (WINDOWS_DRIVE_RE.test(token) || token.startsWith("\\\\")) {
|
||||
return true;
|
||||
}
|
||||
if (token.includes("/") || token.includes("\\")) {
|
||||
return true;
|
||||
}
|
||||
return token.includes("_") && FILE_LIKE_RE.test(token);
|
||||
}
|
||||
|
||||
function normalizeLongTokenForDisplay(token: string): string {
|
||||
// Preserve copy-sensitive tokens exactly (paths/urls/file-like names).
|
||||
if (isCopySensitiveToken(token)) {
|
||||
return token;
|
||||
}
|
||||
return chunkToken(token, MAX_TOKEN_CHARS).join(" ");
|
||||
}
|
||||
|
||||
function redactBinaryLikeLine(line: string): string {
|
||||
const replacementCount = (line.match(REPLACEMENT_CHAR_RE) || []).length;
|
||||
if (
|
||||
@@ -80,7 +112,7 @@ export function sanitizeRenderableText(text: string): string {
|
||||
.join("\n")
|
||||
: withoutControlChars;
|
||||
return LONG_TOKEN_TEST_RE.test(redacted)
|
||||
? redacted.replace(LONG_TOKEN_RE, (token) => chunkToken(token, MAX_TOKEN_CHARS).join(" "))
|
||||
? redacted.replace(LONG_TOKEN_RE, normalizeLongTokenForDisplay)
|
||||
: redacted;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user