-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathwindows.ts
More file actions
103 lines (86 loc) · 2.86 KB
/
windows.ts
File metadata and controls
103 lines (86 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { log, spinner as clackSpinner } from "@clack/prompts";
import { isWindows as stdEnvIsWindows } from "std-env";
export const isWindows = stdEnvIsWindows;
export function escapeImportPath(path: string) {
return isWindows ? path.replaceAll("\\", "\\\\") : path;
}
// Removes ANSI escape sequences to get actual visible length
function getVisibleLength(str: string): number {
return (
str
// Remove terminal hyperlinks: \u001b]8;;URL\u0007TEXT\u001b]8;;\u0007
.replace(/\u001b]8;;[^\u0007]*\u0007/g, "")
// Remove standard ANSI escape sequences (colors, cursor movement, etc.)
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").length
);
}
function truncateMessage(msg: string, maxLength?: number): string {
const terminalWidth = maxLength ?? process.stdout.columns ?? 80;
const availableWidth = terminalWidth - 5; // Reserve some space for the spinner and padding
const visibleLength = getVisibleLength(msg);
if (visibleLength <= availableWidth) {
return msg;
}
// We need to truncate based on visible characters, but preserve ANSI sequences
// Simple approach: truncate character by character until we fit
let truncated = msg;
while (getVisibleLength(truncated) > availableWidth - 3) {
truncated = truncated.slice(0, -1);
}
return truncated + "...";
}
const wrappedClackSpinner = () => {
let currentMessage = "";
let isActive = false;
const handleResize = () => {
if (isActive && currentMessage) {
spinner.message(truncateMessage(currentMessage));
}
};
const spinner = clackSpinner();
return {
start: (msg?: string): void => {
currentMessage = msg ?? "";
isActive = true;
process.stdout.on("resize", handleResize);
spinner.start(truncateMessage(currentMessage));
},
stop: (msg?: string, code?: number): void => {
process.stdout.off("resize", handleResize);
if (!isActive) {
// Spinner was never started, just display the message
if (msg) {
log.message(msg);
}
return;
}
isActive = false;
spinner.stop(truncateMessage(msg ?? ""), code);
},
message: (msg?: string): void => {
currentMessage = msg ?? "";
if (!isActive) {
// Spinner was never started, just display the message
if (msg) {
log.message(msg);
}
return;
}
spinner.message(truncateMessage(currentMessage));
},
};
};
const ballmerSpinner = () => ({
start: (msg?: string): void => {
log.step(msg ?? "");
},
stop: (msg?: string, code?: number): void => {
log.message(msg ?? "");
},
message: (msg?: string): void => {
log.message(msg ?? "");
},
});
// This will become unecessary with the next clack release, the bug was fixed here:
// https://github.com/natemoo-re/clack/pull/182
export const spinner = () => (isWindows ? ballmerSpinner() : wrappedClackSpinner());