@@ -21,6 +21,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
2121import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService' ;
2222import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance' ;
2323import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
24+ import { isLowSurrogate , isHighSurrogate } from 'vs/base/common/strings' ;
2425
2526export interface ICancelEvent {
2627 readonly retrigger : boolean ;
@@ -95,7 +96,7 @@ export class SuggestModel implements IDisposable {
9596
9697 private readonly _toDispose = new DisposableStore ( ) ;
9798 private _quickSuggestDelay : number = 10 ;
98- private _triggerCharacterListener ?: IDisposable ;
99+ private readonly _triggerCharacterListener = new DisposableStore ( ) ;
99100 private readonly _triggerQuickSuggest = new TimeoutTimer ( ) ;
100101 private _state : State = State . Idle ;
101102
@@ -181,8 +182,7 @@ export class SuggestModel implements IDisposable {
181182 }
182183
183184 private _updateTriggerCharacters ( ) : void {
184-
185- dispose ( this . _triggerCharacterListener ) ;
185+ this . _triggerCharacterListener . clear ( ) ;
186186
187187 if ( this . _editor . getOption ( EditorOption . readOnly )
188188 || ! this . _editor . hasModel ( )
@@ -191,29 +191,49 @@ export class SuggestModel implements IDisposable {
191191 return ;
192192 }
193193
194- const supportsByTriggerCharacter : { [ ch : string ] : Set < CompletionItemProvider > } = Object . create ( null ) ;
194+ const supportsByTriggerCharacter = new Map < string , Set < CompletionItemProvider > > ( ) ;
195195 for ( const support of CompletionProviderRegistry . all ( this . _editor . getModel ( ) ) ) {
196196 for ( const ch of support . triggerCharacters || [ ] ) {
197- let set = supportsByTriggerCharacter [ ch ] ;
197+ let set = supportsByTriggerCharacter . get ( ch ) ;
198198 if ( ! set ) {
199- set = supportsByTriggerCharacter [ ch ] = new Set ( ) ;
199+ set = new Set ( ) ;
200200 set . add ( getSnippetSuggestSupport ( ) ) ;
201+ supportsByTriggerCharacter . set ( ch , set ) ;
201202 }
202203 set . add ( support ) ;
203204 }
204205 }
205206
206- this . _triggerCharacterListener = this . _editor . onDidType ( text => {
207- const lastChar = text . charAt ( text . length - 1 ) ;
208- const supports = supportsByTriggerCharacter [ lastChar ] ;
209207
208+ const checkTriggerCharacter = ( text ?: string ) => {
209+
210+ if ( ! text ) {
211+ // came here from the compositionEnd-event
212+ const position = this . _editor . getPosition ( ) ! ;
213+ const model = this . _editor . getModel ( ) ! ;
214+ text = model . getLineContent ( position . lineNumber ) . substr ( 0 , position . column - 1 ) ;
215+ }
216+
217+ let lastChar = '' ;
218+ if ( isLowSurrogate ( text . charCodeAt ( text . length - 1 ) ) ) {
219+ if ( isHighSurrogate ( text . charCodeAt ( text . length - 2 ) ) ) {
220+ lastChar = text . substr ( text . length - 2 ) ;
221+ }
222+ } else {
223+ lastChar = text . charAt ( text . length - 1 ) ;
224+ }
225+
226+ const supports = supportsByTriggerCharacter . get ( lastChar ) ;
210227 if ( supports ) {
211228 // keep existing items that where not computed by the
212229 // supports/providers that want to trigger now
213230 const items : CompletionItem [ ] | undefined = this . _completionModel ? this . _completionModel . adopt ( supports ) : undefined ;
214231 this . trigger ( { auto : true , shy : false , triggerCharacter : lastChar } , Boolean ( this . _completionModel ) , supports , items ) ;
215232 }
216- } ) ;
233+ } ;
234+
235+ this . _triggerCharacterListener . add ( this . _editor . onDidType ( checkTriggerCharacter ) ) ;
236+ this . _triggerCharacterListener . add ( this . _editor . onCompositionEnd ( checkTriggerCharacter ) ) ;
217237 }
218238
219239 // --- trigger/retrigger/cancel suggest
0 commit comments