@@ -7,6 +7,67 @@ export function escapeImportPath(path: string) {
7
7
return isWindows ? path . replaceAll ( "\\" , "\\\\" ) : path ;
8
8
}
9
9
10
+ // Removes ANSI escape sequences to get actual visible length
11
+ function getVisibleLength ( str : string ) : number {
12
+ return (
13
+ str
14
+ // Remove terminal hyperlinks: \u001b]8;;URL\u0007TEXT\u001b]8;;\u0007
15
+ . replace ( / \u001b ] 8 ; ; [ ^ \u0007 ] * \u0007 / g, "" )
16
+ // Remove standard ANSI escape sequences (colors, cursor movement, etc.)
17
+ . replace ( / \x1b \[ [ 0 - 9 ; ] * [ a - z A - Z ] / g, "" ) . length
18
+ ) ;
19
+ }
20
+
21
+ function truncateMessage ( msg : string , maxLength ?: number ) : string {
22
+ const terminalWidth = maxLength ?? process . stdout . columns ?? 80 ;
23
+ const availableWidth = terminalWidth - 5 ; // Reserve some space for the spinner and padding
24
+ const visibleLength = getVisibleLength ( msg ) ;
25
+
26
+ if ( visibleLength <= availableWidth ) {
27
+ return msg ;
28
+ }
29
+
30
+ // We need to truncate based on visible characters, but preserve ANSI sequences
31
+ // Simple approach: truncate character by character until we fit
32
+ let truncated = msg ;
33
+ while ( getVisibleLength ( truncated ) > availableWidth - 3 ) {
34
+ truncated = truncated . slice ( 0 , - 1 ) ;
35
+ }
36
+
37
+ return truncated + "..." ;
38
+ }
39
+
40
+ const wrappedClackSpinner = ( ) => {
41
+ let currentMessage = "" ;
42
+ let isActive = false ;
43
+
44
+ const handleResize = ( ) => {
45
+ if ( isActive && currentMessage ) {
46
+ spinner . message ( truncateMessage ( currentMessage ) ) ;
47
+ }
48
+ } ;
49
+
50
+ const spinner = clackSpinner ( ) ;
51
+
52
+ return {
53
+ start : ( msg ?: string ) : void => {
54
+ currentMessage = msg ?? "" ;
55
+ isActive = true ;
56
+ process . stdout . on ( "resize" , handleResize ) ;
57
+ spinner . start ( truncateMessage ( currentMessage ) ) ;
58
+ } ,
59
+ stop : ( msg ?: string , code ?: number ) : void => {
60
+ isActive = false ;
61
+ process . stdout . off ( "resize" , handleResize ) ;
62
+ spinner . stop ( truncateMessage ( msg ?? "" ) , code ) ;
63
+ } ,
64
+ message : ( msg ?: string ) : void => {
65
+ currentMessage = msg ?? "" ;
66
+ spinner . message ( truncateMessage ( currentMessage ) ) ;
67
+ } ,
68
+ } ;
69
+ } ;
70
+
10
71
const ballmerSpinner = ( ) => ( {
11
72
start : ( msg ?: string ) : void => {
12
73
log . step ( msg ?? "" ) ;
@@ -21,4 +82,4 @@ const ballmerSpinner = () => ({
21
82
22
83
// This will become unecessary with the next clack release, the bug was fixed here:
23
84
// https://github.com/natemoo-re/clack/pull/182
24
- export const spinner = ( ) => ( isWindows ? ballmerSpinner ( ) : clackSpinner ( ) ) ;
85
+ export const spinner = ( ) => ( isWindows ? ballmerSpinner ( ) : wrappedClackSpinner ( ) ) ;
0 commit comments