1414// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
1515// *****************************************************************************
1616
17- import { Terminal , RendererType } from 'xterm' ;
17+ import { Terminal } from 'xterm' ;
1818import { FitAddon } from 'xterm-addon-fit' ;
1919import { inject , injectable , named , postConstruct } from '@theia/core/shared/inversify' ;
2020import { ContributionProvider , Disposable , Event , Emitter , ILogger , DisposableCollection , Channel , OS } from '@theia/core' ;
@@ -32,7 +32,7 @@ import {
3232 TerminalLocation
3333} from './base/terminal-widget' ;
3434import { Deferred } from '@theia/core/lib/common/promise-util' ;
35- import { TerminalPreferences , TerminalRendererType , isTerminalRendererType , DEFAULT_TERMINAL_RENDERER_TYPE , CursorStyle } from './terminal-preferences' ;
35+ import { TerminalPreferences } from './terminal-preferences' ;
3636import URI from '@theia/core/lib/common/uri' ;
3737import { TerminalService } from './base/terminal-service' ;
3838import { TerminalSearchWidgetFactory , TerminalSearchWidget } from './search/terminal-search-widget' ;
@@ -161,7 +161,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
161161
162162 this . term = new Terminal ( {
163163 cursorBlink : this . preferences [ 'terminal.integrated.cursorBlinking' ] ,
164- cursorStyle : this . getCursorStyle ( ) ,
164+ cursorStyle : this . preferences [ 'terminal.integrated.cursorStyle' ] === 'line' ? 'bar' : this . preferences [ 'terminal.integrated.cursorStyle' ] ,
165165 cursorWidth : this . preferences [ 'terminal.integrated.cursorWidth' ] ,
166166 fontFamily : this . preferences [ 'terminal.integrated.fontFamily' ] ,
167167 fontSize : this . preferences [ 'terminal.integrated.fontSize' ] ,
@@ -172,7 +172,6 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
172172 lineHeight : this . preferences [ 'terminal.integrated.lineHeight' ] ,
173173 scrollback : this . preferences [ 'terminal.integrated.scrollback' ] ,
174174 fastScrollSensitivity : this . preferences [ 'terminal.integrated.fastScrollSensitivity' ] ,
175- rendererType : this . getTerminalRendererType ( this . preferences [ 'terminal.integrated.rendererType' ] ) ,
176175 theme : this . themeService . theme
177176 } ) ;
178177
@@ -182,34 +181,12 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
182181 this . initializeLinkHover ( ) ;
183182
184183 this . toDispose . push ( this . preferences . onPreferenceChanged ( change => {
185- const lastSeparator = change . preferenceName . lastIndexOf ( '.' ) ;
186- if ( lastSeparator > 0 ) {
187- let preferenceName = change . preferenceName . substring ( lastSeparator + 1 ) ;
188- let preferenceValue = change . newValue ;
189-
190- if ( preferenceName === 'rendererType' ) {
191- const newRendererType = preferenceValue as string ;
192- if ( newRendererType !== this . getTerminalRendererType ( newRendererType ) ) {
193- // Given terminal renderer type is not supported or invalid
194- preferenceValue = DEFAULT_TERMINAL_RENDERER_TYPE ;
195- }
196- } else if ( preferenceName === 'cursorBlinking' ) {
197- // Convert the terminal preference into a valid `xterm` option
198- preferenceName = 'cursorBlink' ;
199- } else if ( preferenceName === 'cursorStyle' ) {
200- preferenceValue = this . getCursorStyle ( ) ;
201- }
202- try {
203- this . term . setOption ( preferenceName , preferenceValue ) ;
204- } catch ( e ) {
205- console . debug ( `xterm configuration: '${ preferenceName } ' with value '${ preferenceValue } ' is not valid.` ) ;
206- }
207- this . needsResize = true ;
208- this . update ( ) ;
209- }
184+ this . updateConfig ( ) ;
185+ this . needsResize = true ;
186+ this . update ( ) ;
210187 } ) ) ;
211188
212- this . toDispose . push ( this . themeService . onDidChange ( ( ) => this . term . setOption ( ' theme' , this . themeService . theme ) ) ) ;
189+ this . toDispose . push ( this . themeService . onDidChange ( ( ) => this . term . options . theme = this . themeService . theme ) ) ;
213190 this . attachCustomKeyEventHandler ( ) ;
214191 const titleChangeListenerDispose = this . term . onTitleChange ( ( title : string ) => {
215192 if ( this . options . useServerTitle ) {
@@ -314,25 +291,38 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
314291 return this . terminalKind ;
315292 }
316293
317- /**
318- * Get the cursor style compatible with `xterm`.
319- * @returns CursorStyle
320- */
321- private getCursorStyle ( ) : CursorStyle {
322- const value = this . preferences [ 'terminal.integrated.cursorStyle' ] ;
323- return value === 'line' ? 'bar' : value ;
294+ updateConfig ( ) : void {
295+ this . setCursorBlink ( this . preferences . get ( 'terminal.integrated.cursorBlinking' ) ) ;
296+ this . setCursorStyle ( this . preferences . get ( 'terminal.integrated.cursorStyle' ) ) ;
297+ this . setCursorWidth ( this . preferences . get ( 'terminal.integrated.cursorWidth' ) ) ;
298+ this . term . options . fontFamily = this . preferences . get ( 'terminal.integrated.fontFamily' ) ;
299+ this . term . options . fontSize = this . preferences . get ( 'terminal.integrated.fontSize' ) ;
300+ this . term . options . fontWeight = this . preferences . get ( 'terminal.integrated.fontWeight' ) ;
301+ this . term . options . fontWeightBold = this . preferences . get ( 'terminal.integrated.fontWeightBold' ) ;
302+ this . term . options . drawBoldTextInBrightColors = this . preferences . get ( 'terminal.integrated.drawBoldTextInBrightColors' ) ;
303+ this . term . options . letterSpacing = this . preferences . get ( 'terminal.integrated.letterSpacing' ) ;
304+ this . term . options . lineHeight = this . preferences . get ( 'terminal.integrated.lineHeight' ) ;
305+ this . term . options . scrollback = this . preferences . get ( 'terminal.integrated.scrollback' ) ;
306+ this . term . options . fastScrollSensitivity = this . preferences . get ( 'terminal.integrated.fastScrollSensitivity' ) ;
324307 }
325308
326- /**
327- * Returns given renderer type if it is valid and supported or default renderer otherwise.
328- *
329- * @param terminalRendererType desired terminal renderer type
330- */
331- private getTerminalRendererType ( terminalRendererType ?: string | TerminalRendererType ) : RendererType {
332- if ( terminalRendererType && isTerminalRendererType ( terminalRendererType ) ) {
333- return terminalRendererType ;
309+ private setCursorBlink ( blink : boolean ) : void {
310+ if ( this . term . options . cursorBlink !== blink ) {
311+ this . term . options . cursorBlink = blink ;
312+ this . term . refresh ( 0 , this . term . rows - 1 ) ;
313+ }
314+ }
315+
316+ private setCursorStyle ( style : 'block' | 'underline' | 'bar' | 'line' ) : void {
317+ if ( this . term . options . cursorStyle !== style ) {
318+ this . term . options . cursorStyle = ( style === 'line' ) ? 'bar' : style ;
319+ }
320+ }
321+
322+ private setCursorWidth ( width : number ) : void {
323+ if ( this . term . options . cursorWidth !== width ) {
324+ this . term . options . cursorWidth = width ;
334325 }
335- return DEFAULT_TERMINAL_RENDERER_TYPE ;
336326 }
337327
338328 protected initializeLinkHover ( ) : void {
@@ -670,16 +660,34 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
670660 }
671661 this . term . open ( this . node ) ;
672662
663+ interface ViewportType {
664+ register ( d : Disposable ) : void ;
665+ _refreshAnimationFrame : number | null ;
666+ _coreBrowserService : {
667+ window : Window ;
668+ }
669+ }
670+
671+ // Workaround for https://github.com/xtermjs/xterm.js/issues/4775. Can be removed for releases > 5.3.0
672+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
673+ const viewPort : ViewportType = ( this . term as any ) . _core . viewport ;
674+ viewPort . register ( Disposable . create ( ( ) => {
675+ if ( typeof viewPort . _refreshAnimationFrame === 'number' ) {
676+ viewPort . _coreBrowserService . window . cancelAnimationFrame ( viewPort . _refreshAnimationFrame ) ;
677+ }
678+ } ) ) ;
679+
673680 if ( isFirefox ) {
674681 // monkey patching intersection observer handling for secondary window support
675682 // eslint-disable-next-line @typescript-eslint/no-explicit-any
676683 const renderService : any = ( this . term as any ) . _core . _renderService ;
677- const originalFunc : ( entry : IntersectionObserverEntry ) => void = renderService . _onIntersectionChange . bind ( renderService ) ;
684+
685+ const originalFunc : ( entry : IntersectionObserverEntry ) => void = renderService . _handleIntersectionChange . bind ( renderService ) ;
678686 const replacement = function ( entry : IntersectionObserverEntry ) : void {
679687 if ( entry . target . ownerDocument !== document ) {
680688 // in Firefox, the intersection observer always reports the widget as non-intersecting if the dom element
681689 // is in a different document from when the IntersectionObserver started observing. Since we know
682- // that the widget is always "visible" when in a secondary window, so we mark the entry as "intersecting"
690+ // that the widget is always "visible" when in a secondary window, so we refresh the rows ourselves
683691 const patchedEvent : IntersectionObserverEntry = {
684692 ...entry ,
685693 isIntersecting : true ,
@@ -690,21 +698,14 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
690698 }
691699 } ;
692700
693- renderService . _onIntersectionChange = replacement ;
701+ renderService . _handleIntersectionChange = replacement . bind ( renderService ) ;
694702 }
695703
696704 if ( this . initialData ) {
697705 this . term . write ( this . initialData ) ;
698706 }
699707 this . termOpened = true ;
700708 this . initialData = '' ;
701-
702- if ( isFirefox ) {
703- // The software scrollbars don't work with xterm.js, so we disable the scrollbar if we are on firefox.
704- if ( this . term . element ) {
705- ( this . term . element . children . item ( 0 ) as HTMLElement ) . style . overflow = 'hidden' ;
706- }
707- }
708709 }
709710
710711 write ( data : string ) : void {
@@ -792,11 +793,13 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
792793 return ;
793794 }
794795 const geo = this . fitAddon . proposeDimensions ( ) ;
795- const cols = geo . cols ;
796- const rows = geo . rows - 1 ; // subtract one row for margin
797- this . term . resize ( cols , rows ) ;
796+ if ( geo ) {
797+ const cols = geo . cols ;
798+ const rows = geo . rows - 1 ; // subtract one row for margin
799+ this . term . resize ( cols , rows ) ;
798800
799- this . resizeTerminalProcess ( ) ;
801+ this . resizeTerminalProcess ( ) ;
802+ }
800803 }
801804
802805 protected resizeTerminalProcess ( ) : void {
0 commit comments