@@ -137,14 +137,8 @@ function Terminal(options) {
137137 */
138138 this . y = 0 ;
139139
140- /**
141- * Used to debounce the refresh function
142- */
143- this . isRefreshing = false ;
144-
145- /**
146- * Whether there is a full terminal refresh queued
147- */
140+ /** A queue of the rows to be refreshed */
141+ this . refreshRowsQueue = [ ] ;
148142
149143 this . cursorState = 0 ;
150144 this . cursorHidden = false ;
@@ -407,7 +401,7 @@ Terminal.prototype.blur = function() {
407401 */
408402Terminal . bindBlur = function ( term ) {
409403 on ( term . textarea , 'blur' , function ( ev ) {
410- term . refresh ( term . y , term . y ) ;
404+ term . queueRefresh ( term . y , term . y ) ;
411405 if ( term . sendFocus ) {
412406 term . send ( '\x1b[O' ) ;
413407 }
@@ -585,8 +579,9 @@ Terminal.prototype.open = function(parent) {
585579
586580 this . viewport = new Viewport ( this , this . viewportElement , this . viewportScrollArea , this . charMeasureElement ) ;
587581
588- // Draw the screen.
589- this . refresh ( 0 , this . rows - 1 ) ;
582+ // Setup loop that draws to screen
583+ this . queueRefresh ( 0 , this . rows - 1 ) ;
584+ this . refreshLoop ( ) ;
590585
591586 // Initialize global actions that
592587 // need to be taken on the document.
@@ -997,6 +992,48 @@ Terminal.flags = {
997992 INVISIBLE : 16
998993}
999994
995+ /**
996+ * Queues a refresh between two rows (inclusive), to be done on next animation
997+ * frame.
998+ * @param {number } start The start row.
999+ * @param {number } end The end row.
1000+ */
1001+ Terminal . prototype . queueRefresh = function ( start , end ) {
1002+ this . refreshRowsQueue . push ( { start : start , end : end } ) ;
1003+ }
1004+
1005+ /**
1006+ * Performs the refresh loop callback, calling refresh only if a refresh is
1007+ * necessary before queueing up the next one.
1008+ */
1009+ Terminal . prototype . refreshLoop = function ( ) {
1010+ // Don't refresh if there were no row changes
1011+ if ( this . refreshRowsQueue . length > 0 ) {
1012+ var start ;
1013+ var end ;
1014+ if ( this . refreshRowsQueue . length > 4 ) {
1015+ // Just do a full refresh when 5+ refreshes are queued
1016+ start = 0 ;
1017+ end = this . rows - 1 ;
1018+ } else {
1019+ // Get start and end rows that need refreshing
1020+ start = this . refreshRowsQueue [ 0 ] . start ;
1021+ end = this . refreshRowsQueue [ 0 ] . end ;
1022+ for ( var i = 1 ; i < this . refreshRowsQueue . length ; i ++ ) {
1023+ if ( this . refreshRowsQueue [ i ] . start < start ) {
1024+ start = this . refreshRowsQueue [ i ] . start ;
1025+ }
1026+ if ( this . refreshRowsQueue [ i ] . end > end ) {
1027+ end = this . refreshRowsQueue [ i ] . end ;
1028+ }
1029+ }
1030+ }
1031+ this . refreshRowsQueue = [ ] ;
1032+ this . refresh ( start , end ) ;
1033+ }
1034+ window . requestAnimationFrame ( this . refreshLoop . bind ( this ) ) ;
1035+ }
1036+
10001037/**
10011038 * Refreshes (re-renders) terminal content within two rows (inclusive)
10021039 *
@@ -1017,47 +1054,10 @@ Terminal.flags = {
10171054 *
10181055 * @param {number } start The row to start from (between 0 and terminal's height terminal - 1)
10191056 * @param {number } end The row to end at (between fromRow and terminal's height terminal - 1)
1020- * @param {boolean } queue Whether the refresh should ran right now or be queued
10211057 */
1022- Terminal . prototype . refresh = function ( start , end , queue ) {
1058+ Terminal . prototype . refresh = function ( start , end ) {
10231059 var self = this ;
10241060
1025- // queue defaults to true
1026- queue = ( typeof queue == 'undefined' ) ? true : queue ;
1027-
1028- /**
1029- * The refresh queue allows refresh to execute only approximately 30 times a second. For
1030- * commands that pass a significant amount of output to the write function, this prevents the
1031- * terminal from maxing out the CPU and making the UI unresponsive. While commands can still
1032- * run beyond what they do on the terminal, it is far better with a debounce in place as
1033- * every single terminal manipulation does not need to be constructed in the DOM.
1034- *
1035- * A side-effect of this is that it makes ^C to interrupt a process seem more responsive.
1036- */
1037- if ( queue ) {
1038- // If refresh should be queued, order the refresh and return.
1039- if ( this . _refreshIsQueued ) {
1040- // If a refresh has already been queued, just order a full refresh next
1041- this . _fullRefreshNext = true ;
1042- } else {
1043- setTimeout ( function ( ) {
1044- self . refresh ( start , end , false ) ;
1045- } , 34 )
1046- this . _refreshIsQueued = true ;
1047- }
1048- return ;
1049- }
1050-
1051- // If refresh should be run right now (not be queued), release the lock
1052- this . _refreshIsQueued = false ;
1053-
1054- // If multiple refreshes were requested, make a full refresh.
1055- if ( this . _fullRefreshNext ) {
1056- start = 0 ;
1057- end = this . rows - 1 ;
1058- this . _fullRefreshNext = false // reset lock
1059- }
1060-
10611061 var x , y , i , line , out , ch , ch_width , width , data , attr , bg , fg , flags , row , parent , focused = document . activeElement ;
10621062
10631063 // If this is a big refresh, remove the terminal rows from the DOM for faster calculations
@@ -1224,7 +1224,7 @@ Terminal.prototype.refresh = function(start, end, queue) {
12241224Terminal . prototype . showCursor = function ( ) {
12251225 if ( ! this . cursorState ) {
12261226 this . cursorState = 1 ;
1227- this . refresh ( this . y , this . y ) ;
1227+ this . queueRefresh ( this . y , this . y ) ;
12281228 }
12291229} ;
12301230
@@ -1311,7 +1311,7 @@ Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) {
13111311 this . emit ( 'scroll' , this . ydisp ) ;
13121312 }
13131313
1314- this . refresh ( 0 , this . rows - 1 ) ;
1314+ this . queueRefresh ( 0 , this . rows - 1 ) ;
13151315} ;
13161316
13171317/**
@@ -2379,7 +2379,7 @@ Terminal.prototype.write = function(data) {
23792379 }
23802380
23812381 this . updateRange ( this . y ) ;
2382- this . refresh ( this . refreshStart , this . refreshEnd ) ;
2382+ this . queueRefresh ( this . refreshStart , this . refreshEnd ) ;
23832383} ;
23842384
23852385/**
@@ -2945,7 +2945,7 @@ Terminal.prototype.resize = function(x, y) {
29452945 this . scrollTop = 0 ;
29462946 this . scrollBottom = y - 1 ;
29472947
2948- this . refresh ( 0 , this . rows - 1 ) ;
2948+ this . queueRefresh ( 0 , this . rows - 1 ) ;
29492949
29502950 this . normal = null ;
29512951
@@ -3074,7 +3074,7 @@ Terminal.prototype.clear = function() {
30743074 for ( var i = 1 ; i < this . rows ; i ++ ) {
30753075 this . lines . push ( this . blankLine ( ) ) ;
30763076 }
3077- this . refresh ( 0 , this . rows - 1 ) ;
3077+ this . queueRefresh ( 0 , this . rows - 1 ) ;
30783078 this . emit ( 'scroll' , this . ydisp ) ;
30793079} ;
30803080
@@ -3205,7 +3205,7 @@ Terminal.prototype.reset = function() {
32053205 var customKeydownHandler = this . customKeydownHandler ;
32063206 Terminal . call ( this , this . options ) ;
32073207 this . customKeydownHandler = customKeydownHandler ;
3208- this . refresh ( 0 , this . rows - 1 ) ;
3208+ this . queueRefresh ( 0 , this . rows - 1 ) ;
32093209 this . viewport . syncScrollArea ( ) ;
32103210} ;
32113211
@@ -4324,7 +4324,7 @@ Terminal.prototype.resetMode = function(params) {
43244324 // this.x = this.savedX;
43254325 // this.y = this.savedY;
43264326 // }
4327- this . refresh ( 0 , this . rows - 1 ) ;
4327+ this . queueRefresh ( 0 , this . rows - 1 ) ;
43284328 this . viewport . syncScrollArea ( ) ;
43294329 this . showCursor ( ) ;
43304330 }
0 commit comments