@@ -25,14 +25,16 @@ const lightTheme: ITheme = {
25
25
selectionBackground : "#add6ff80" , // https://github.com/gitpod-io/gitpod-vscode-theme/blob/6fb17ba8915fcd68fde3055b4bc60642ce5eed14/themes/gitpod-light-color-theme.json#L15
26
26
} ;
27
27
28
- export interface WorkspaceLogsProps {
28
+ export interface Props {
29
29
logsEmitter : EventEmitter ;
30
30
errorMessage ?: string ;
31
31
classes ?: string ;
32
32
xtermClasses ?: string ;
33
33
}
34
34
35
- export default function WorkspaceLogs ( props : WorkspaceLogsProps ) {
35
+ const MAX_CHUNK_SIZE = 1024 * 4 ; // 4KB
36
+
37
+ export default function WorkspaceLogs ( { logsEmitter, errorMessage, classes, xtermClasses } : Props ) {
36
38
const xTermParentRef = useRef < HTMLDivElement > ( null ) ;
37
39
const terminalRef = useRef < Terminal > ( ) ;
38
40
const fitAddon = useMemo ( ( ) => new FitAddon ( ) , [ ] ) ;
@@ -54,17 +56,37 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
54
56
terminal . loadAddon ( fitAddon ) ;
55
57
terminal . open ( xTermParentRef . current ) ;
56
58
57
- const logListener = ( logs : string ) => {
58
- if ( terminal && logs ) {
59
- terminal . write ( logs ) ;
59
+ let logBuffer = "" ;
60
+ let isWriting = false ;
61
+
62
+ const processNextLog = ( ) => {
63
+ if ( isWriting || logBuffer . length === 0 ) return ;
64
+
65
+ const logs = logBuffer . slice ( 0 , MAX_CHUNK_SIZE ) ;
66
+ logBuffer = logBuffer . slice ( logs . length ) ;
67
+ if ( logs ) {
68
+ isWriting = true ;
69
+ terminal . write ( logs , ( ) => {
70
+ isWriting = false ;
71
+ processNextLog ( ) ;
72
+ } ) ;
60
73
}
61
74
} ;
62
75
76
+ const logListener = ( logs : string ) => {
77
+ if ( ! logs ) return ;
78
+
79
+ logBuffer += logs ;
80
+ processNextLog ( ) ;
81
+ } ;
82
+
63
83
const resetListener = ( ) => {
64
84
terminal . clear ( ) ;
85
+ logBuffer = "" ;
86
+ isWriting = false ;
65
87
} ;
66
88
67
- const emitter = props . logsEmitter . on ( "logs" , logListener ) ;
89
+ const emitter = logsEmitter . on ( "logs" , logListener ) ;
68
90
emitter . on ( "reset" , resetListener ) ;
69
91
fitAddon . fit ( ) ;
70
92
@@ -74,7 +96,7 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
74
96
emitter . removeListener ( "reset" , resetListener ) ;
75
97
} ;
76
98
// eslint-disable-next-line react-hooks/exhaustive-deps
77
- } , [ props . logsEmitter ] ) ;
99
+ } , [ logsEmitter ] ) ;
78
100
79
101
const resizeDebounced = debounce (
80
102
( ) => {
@@ -95,11 +117,11 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
95
117
} , [ ] ) ;
96
118
97
119
useEffect ( ( ) => {
98
- if ( terminalRef . current && props . errorMessage ) {
99
- terminalRef . current . write ( `\r\n\u001b[38;5;196m${ props . errorMessage } \u001b[0m\r\n` ) ;
120
+ if ( terminalRef . current && errorMessage ) {
121
+ terminalRef . current . write ( `\r\n\u001b[38;5;196m${ errorMessage } \u001b[0m\r\n` ) ;
100
122
}
101
123
// eslint-disable-next-line react-hooks/exhaustive-deps
102
- } , [ terminalRef . current , props . errorMessage ] ) ;
124
+ } , [ terminalRef . current , errorMessage ] ) ;
103
125
104
126
useEffect ( ( ) => {
105
127
if ( ! terminalRef . current ) {
@@ -112,12 +134,12 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
112
134
return (
113
135
< div
114
136
className = { cn (
115
- props . classes || "mt-6 h-72 w-11/12 lg:w-3/5 rounded-xl overflow-hidden" ,
137
+ classes || "mt-6 h-72 w-11/12 lg:w-3/5 rounded-xl overflow-hidden" ,
116
138
"bg-pk-surface-secondary relative text-left" ,
117
139
) }
118
140
>
119
141
< div
120
- className = { cn ( props . xtermClasses || "absolute top-0 left-0 bottom-0 right-0 m-6" ) }
142
+ className = { cn ( xtermClasses || "absolute top-0 left-0 bottom-0 right-0 m-6" ) }
121
143
ref = { xTermParentRef }
122
144
> </ div >
123
145
</ div >
0 commit comments