@@ -946,29 +946,37 @@ export class PredictionTimeline {
946
946
return buffer . type === 'normal' ? buffer : undefined ;
947
947
}
948
948
}
949
+
949
950
/**
950
- * Gets the escape sequence to restore state/appearence in the cell.
951
+ * Gets the escape sequence args to restore state/appearence in the cell.
951
952
*/
952
- const attributesToSeq = ( cell : XTermAttributes ) => cell . isAttributeDefault ( )
953
- ? `${ CSI } 0m`
954
- : [
955
- cell . isBold ( ) && `${ CSI } 1m` ,
956
- cell . isDim ( ) && `${ CSI } 2m` ,
957
- cell . isItalic ( ) && `${ CSI } 3m` ,
958
- cell . isUnderline ( ) && `${ CSI } 4m` ,
959
- cell . isBlink ( ) && `${ CSI } 5m` ,
960
- cell . isInverse ( ) && `${ CSI } 7m` ,
961
- cell . isInvisible ( ) && `${ CSI } 8m` ,
962
-
963
- cell . isFgRGB ( ) && `${ CSI } 38;2;${ cell . getFgColor ( ) >>> 24 } ;${ ( cell . getFgColor ( ) >>> 16 ) & 0xFF } ;${ cell . getFgColor ( ) & 0xFF } m` ,
964
- cell . isFgPalette ( ) && `${ CSI } 38;5;${ cell . getFgColor ( ) } m` ,
965
- cell . isFgDefault ( ) && `${ CSI } 39m` ,
966
-
967
- cell . isBgRGB ( ) && `${ CSI } 48;2;${ cell . getBgColor ( ) >>> 24 } ;${ ( cell . getBgColor ( ) >>> 16 ) & 0xFF } ;${ cell . getBgColor ( ) & 0xFF } m` ,
968
- cell . isBgPalette ( ) && `${ CSI } 48;5;${ cell . getBgColor ( ) } m` ,
969
- cell . isBgDefault ( ) && `${ CSI } 49m` ,
970
- ] . filter ( seq => ! ! seq ) . join ( '' ) ;
953
+ const attributesToArgs = ( cell : XTermAttributes ) => {
954
+ if ( cell . isAttributeDefault ( ) ) { return [ 0 ] ; }
955
+
956
+ const args = [ ] ;
957
+ if ( cell . isBold ( ) ) { args . push ( 1 ) ; }
958
+ if ( cell . isDim ( ) ) { args . push ( 2 ) ; }
959
+ if ( cell . isItalic ( ) ) { args . push ( 3 ) ; }
960
+ if ( cell . isUnderline ( ) ) { args . push ( 4 ) ; }
961
+ if ( cell . isBlink ( ) ) { args . push ( 5 ) ; }
962
+ if ( cell . isInverse ( ) ) { args . push ( 7 ) ; }
963
+ if ( cell . isInvisible ( ) ) { args . push ( 8 ) ; }
964
+
965
+ if ( cell . isFgRGB ( ) ) { args . push ( 38 , 2 , cell . getFgColor ( ) >>> 24 , ( cell . getFgColor ( ) >>> 16 ) & 0xFF , cell . getFgColor ( ) & 0xFF ) ; }
966
+ if ( cell . isFgPalette ( ) ) { args . push ( 38 , 5 , cell . getFgColor ( ) ) ; }
967
+ if ( cell . isFgDefault ( ) ) { args . push ( 39 ) ; }
968
+
969
+ if ( cell . isBgRGB ( ) ) { args . push ( 48 , 2 , cell . getBgColor ( ) >>> 24 , ( cell . getBgColor ( ) >>> 16 ) & 0xFF , cell . getBgColor ( ) & 0xFF ) ; }
970
+ if ( cell . isBgPalette ( ) ) { args . push ( 48 , 5 , cell . getBgColor ( ) ) ; }
971
+ if ( cell . isBgDefault ( ) ) { args . push ( 49 ) ; }
972
+
973
+ return args ;
974
+ } ;
971
975
976
+ /**
977
+ * Gets the escape sequence to restore state/appearence in the cell.
978
+ */
979
+ const attributesToSeq = ( cell : XTermAttributes ) => `${ CSI } ${ attributesToArgs ( cell ) . join ( ';' ) } m` ;
972
980
973
981
const arrayHasPrefixAt = < T > ( a : ReadonlyArray < T > , ai : number , b : ReadonlyArray < T > ) => {
974
982
if ( a . length - ai > b . length ) {
@@ -1019,7 +1027,7 @@ const getColorWidth = (params: (number | number[])[], pos: number) => {
1019
1027
return advance ;
1020
1028
} ;
1021
1029
1022
- class TypeAheadStyle {
1030
+ class TypeAheadStyle implements IDisposable {
1023
1031
private static compileArgs ( args : ReadonlyArray < number > ) {
1024
1032
return `${ CSI } ${ args . join ( ';' ) } m` ;
1025
1033
}
@@ -1035,8 +1043,9 @@ class TypeAheadStyle {
1035
1043
1036
1044
public apply ! : string ;
1037
1045
public undo ! : string ;
1046
+ private csiHandler ?: IDisposable ;
1038
1047
1039
- constructor ( value : ITerminalConfiguration [ 'localEchoStyle' ] ) {
1048
+ constructor ( value : ITerminalConfiguration [ 'localEchoStyle' ] , private readonly terminal : Terminal ) {
1040
1049
this . onUpdate ( value ) ;
1041
1050
}
1042
1051
@@ -1049,9 +1058,38 @@ class TypeAheadStyle {
1049
1058
}
1050
1059
1051
1060
/**
1052
- * Should be called when an attribut eupdate happens in the terminal.
1061
+ * Starts tracking for CSI changes in the terminal.
1062
+ */
1063
+ public startTracking ( ) {
1064
+ this . expectedIncomingStyles = 0 ;
1065
+ this . onDidWriteSGR ( attributesToArgs ( core ( this . terminal ) . _inputHandler . _curAttrData ) ) ;
1066
+ this . csiHandler = this . terminal . parser . registerCsiHandler ( { final : 'm' } , args => {
1067
+ this . onDidWriteSGR ( args ) ;
1068
+ return false ;
1069
+ } ) ;
1070
+ }
1071
+
1072
+ /**
1073
+ * Stops tracking terminal CSI changes.
1053
1074
*/
1054
- public onDidWriteSGR ( args : ( number | number [ ] ) [ ] ) {
1075
+ @debounce ( 2000 )
1076
+ public debounceStopTracking ( ) {
1077
+ this . stopTracking ( ) ;
1078
+ }
1079
+
1080
+ /**
1081
+ * @inheritdoc
1082
+ */
1083
+ public dispose ( ) {
1084
+ this . stopTracking ( ) ;
1085
+ }
1086
+
1087
+ private stopTracking ( ) {
1088
+ this . csiHandler ?. dispose ( ) ;
1089
+ this . csiHandler = undefined ;
1090
+ }
1091
+
1092
+ private onDidWriteSGR ( args : ( number | number [ ] ) [ ] ) {
1055
1093
const originalUndo = this . undoArgs ;
1056
1094
for ( let i = 0 ; i < args . length ; ) {
1057
1095
const px = args [ i ] ;
@@ -1141,7 +1179,7 @@ class TypeAheadStyle {
1141
1179
}
1142
1180
1143
1181
export class TypeAheadAddon extends Disposable implements ITerminalAddon {
1144
- private typeaheadStyle = new TypeAheadStyle ( this . config . config . localEchoStyle ) ;
1182
+ private typeaheadStyle ?: TypeAheadStyle ;
1145
1183
private typeaheadThreshold = this . config . config . localEchoLatencyThreshold ;
1146
1184
protected lastRow ?: { y : number ; startingX : number } ;
1147
1185
private timeline ?: PredictionTimeline ;
@@ -1162,22 +1200,19 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon {
1162
1200
}
1163
1201
1164
1202
public activate ( terminal : Terminal ) : void {
1203
+ const style = this . typeaheadStyle = this . _register ( new TypeAheadStyle ( this . config . config . localEchoStyle , terminal ) ) ;
1165
1204
const timeline = this . timeline = new PredictionTimeline ( terminal , this . typeaheadStyle ) ;
1166
1205
const stats = this . stats = this . _register ( new PredictionStats ( this . timeline ) ) ;
1167
1206
1168
1207
timeline . setShowPredictions ( this . typeaheadThreshold === 0 ) ;
1169
- this . _register ( terminal . parser . registerCsiHandler ( { final : 'm' } , args => {
1170
- this . typeaheadStyle . onDidWriteSGR ( args ) ;
1171
- return false ;
1172
- } ) ) ;
1173
1208
this . _register ( terminal . onData ( e => this . onUserData ( e ) ) ) ;
1174
1209
this . _register ( terminal . onResize ( ( ) => {
1175
1210
timeline . setShowPredictions ( false ) ;
1176
1211
timeline . clearCursor ( ) ;
1177
1212
this . reevaluatePredictorState ( stats , timeline ) ;
1178
1213
} ) ) ;
1179
1214
this . _register ( this . config . onConfigChanged ( ( ) => {
1180
- this . typeaheadStyle . onUpdate ( this . config . config . localEchoStyle ) ;
1215
+ style . onUpdate ( this . config . config . localEchoStyle ) ;
1181
1216
this . typeaheadThreshold = this . config . config . localEchoLatencyThreshold ;
1182
1217
this . reevaluatePredictorState ( stats , timeline ) ;
1183
1218
} ) ) ;
@@ -1192,6 +1227,10 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon {
1192
1227
} , statsSendTelemetryEvery ) ;
1193
1228
}
1194
1229
1230
+ if ( timeline . length === 0 ) {
1231
+ style . debounceStopTracking ( ) ;
1232
+ }
1233
+
1195
1234
this . reevaluatePredictorState ( stats , timeline ) ;
1196
1235
} ) ) ;
1197
1236
}
@@ -1306,7 +1345,7 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon {
1306
1345
1307
1346
if ( reader . eatCharCode ( 32 , 126 ) ) { // alphanum
1308
1347
const char = data [ reader . index - 1 ] ;
1309
- if ( this . timeline . addPrediction ( buffer , new CharacterPrediction ( this . typeaheadStyle , char ) ) && this . timeline . getCursor ( buffer ) . x === terminal . cols ) {
1348
+ if ( this . timeline . addPrediction ( buffer , new CharacterPrediction ( this . typeaheadStyle ! , char ) ) && this . timeline . getCursor ( buffer ) . x === terminal . cols ) {
1310
1349
this . timeline . addBoundary ( buffer , new TentativeBoundary ( new LinewrapPrediction ( ) ) ) ;
1311
1350
}
1312
1351
continue ;
@@ -1346,6 +1385,7 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon {
1346
1385
1347
1386
if ( this . timeline . length === 1 ) {
1348
1387
this . deferClearingPredictions ( ) ;
1388
+ this . typeaheadStyle ! . startTracking ( ) ;
1349
1389
}
1350
1390
}
1351
1391
0 commit comments