f259335df9055b2085f0f676b9daadb9e502adf7e4e303dd6d115aa70a32de94f4c2ef0c95bf411500eadee9af498b54d123ecbe5274b0b072a2914663e240 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. };
  23. import { TimeoutTimer } from '../../../../base/common/async.js';
  24. import { CancellationTokenSource } from '../../../../base/common/cancellation.js';
  25. import { onUnexpectedError } from '../../../../base/common/errors.js';
  26. import { Emitter } from '../../../../base/common/event.js';
  27. import { DisposableStore, dispose } from '../../../../base/common/lifecycle.js';
  28. import { getLeadingWhitespace, isHighSurrogate, isLowSurrogate } from '../../../../base/common/strings.js';
  29. import { Selection } from '../../../common/core/selection.js';
  30. import { IEditorWorkerService } from '../../../common/services/editorWorker.js';
  31. import { SnippetController2 } from '../../snippet/browser/snippetController2.js';
  32. import { WordDistance } from './wordDistance.js';
  33. import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
  34. import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  35. import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
  36. import { ILogService } from '../../../../platform/log/common/log.js';
  37. import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
  38. import { CompletionModel } from './completionModel.js';
  39. import { CompletionOptions, getSnippetSuggestSupport, getSuggestionComparator, provideSuggestionItems, QuickSuggestionsOptions } from './suggest.js';
  40. import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
  41. export class LineContext {
  42. constructor(model, position, auto, shy, noSelect) {
  43. this.leadingLineContent = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
  44. this.leadingWord = model.getWordUntilPosition(position);
  45. this.lineNumber = position.lineNumber;
  46. this.column = position.column;
  47. this.auto = auto;
  48. this.shy = shy;
  49. this.noSelect = noSelect;
  50. }
  51. static shouldAutoTrigger(editor) {
  52. if (!editor.hasModel()) {
  53. return false;
  54. }
  55. const model = editor.getModel();
  56. const pos = editor.getPosition();
  57. model.tokenization.tokenizeIfCheap(pos.lineNumber);
  58. const word = model.getWordAtPosition(pos);
  59. if (!word) {
  60. return false;
  61. }
  62. if (word.endColumn !== pos.column) {
  63. return false;
  64. }
  65. if (!isNaN(Number(word.word))) {
  66. return false;
  67. }
  68. return true;
  69. }
  70. }
  71. function isSuggestPreviewEnabled(editor) {
  72. return editor.getOption(108 /* EditorOption.suggest */).preview;
  73. }
  74. function canShowQuickSuggest(editor, contextKeyService, configurationService) {
  75. if (!Boolean(contextKeyService.getContextKeyValue('inlineSuggestionVisible'))) {
  76. // Allow if there is no inline suggestion.
  77. return true;
  78. }
  79. const allowQuickSuggestions = configurationService.getValue('editor.inlineSuggest.allowQuickSuggestions');
  80. if (allowQuickSuggestions !== undefined) {
  81. // Use setting if available.
  82. return Boolean(allowQuickSuggestions);
  83. }
  84. // Don't allow if inline suggestions are visible and no suggest preview is configured.
  85. // TODO disabled for copilot
  86. return false && isSuggestPreviewEnabled(editor);
  87. }
  88. function canShowSuggestOnTriggerCharacters(editor, contextKeyService, configurationService) {
  89. if (!Boolean(contextKeyService.getContextKeyValue('inlineSuggestionVisible'))) {
  90. // Allow if there is no inline suggestion.
  91. return true;
  92. }
  93. const allowQuickSuggestions = configurationService.getValue('editor.inlineSuggest.allowSuggestOnTriggerCharacters');
  94. if (allowQuickSuggestions !== undefined) {
  95. // Use setting if available.
  96. return Boolean(allowQuickSuggestions);
  97. }
  98. // Don't allow if inline suggestions are visible and no suggest preview is configured.
  99. // TODO disabled for copilot
  100. return false && isSuggestPreviewEnabled(editor);
  101. }
  102. let SuggestModel = class SuggestModel {
  103. constructor(_editor, _editorWorkerService, _clipboardService, _telemetryService, _logService, _contextKeyService, _configurationService, _languageFeaturesService) {
  104. this._editor = _editor;
  105. this._editorWorkerService = _editorWorkerService;
  106. this._clipboardService = _clipboardService;
  107. this._telemetryService = _telemetryService;
  108. this._logService = _logService;
  109. this._contextKeyService = _contextKeyService;
  110. this._configurationService = _configurationService;
  111. this._languageFeaturesService = _languageFeaturesService;
  112. this._toDispose = new DisposableStore();
  113. this._triggerCharacterListener = new DisposableStore();
  114. this._triggerQuickSuggest = new TimeoutTimer();
  115. this._state = 0 /* State.Idle */;
  116. this._completionDisposables = new DisposableStore();
  117. this._onDidCancel = new Emitter();
  118. this._onDidTrigger = new Emitter();
  119. this._onDidSuggest = new Emitter();
  120. this.onDidCancel = this._onDidCancel.event;
  121. this.onDidTrigger = this._onDidTrigger.event;
  122. this.onDidSuggest = this._onDidSuggest.event;
  123. this._telemetryGate = 0;
  124. this._currentSelection = this._editor.getSelection() || new Selection(1, 1, 1, 1);
  125. // wire up various listeners
  126. this._toDispose.add(this._editor.onDidChangeModel(() => {
  127. this._updateTriggerCharacters();
  128. this.cancel();
  129. }));
  130. this._toDispose.add(this._editor.onDidChangeModelLanguage(() => {
  131. this._updateTriggerCharacters();
  132. this.cancel();
  133. }));
  134. this._toDispose.add(this._editor.onDidChangeConfiguration(() => {
  135. this._updateTriggerCharacters();
  136. }));
  137. this._toDispose.add(this._languageFeaturesService.completionProvider.onDidChange(() => {
  138. this._updateTriggerCharacters();
  139. this._updateActiveSuggestSession();
  140. }));
  141. let editorIsComposing = false;
  142. this._toDispose.add(this._editor.onDidCompositionStart(() => {
  143. editorIsComposing = true;
  144. }));
  145. this._toDispose.add(this._editor.onDidCompositionEnd(() => {
  146. editorIsComposing = false;
  147. this._onCompositionEnd();
  148. }));
  149. this._toDispose.add(this._editor.onDidChangeCursorSelection(e => {
  150. // only trigger suggest when the editor isn't composing a character
  151. if (!editorIsComposing) {
  152. this._onCursorChange(e);
  153. }
  154. }));
  155. this._toDispose.add(this._editor.onDidChangeModelContent(() => {
  156. // only filter completions when the editor isn't composing a character
  157. // allow-any-unicode-next-line
  158. // e.g. ¨ + u makes ü but just ¨ cannot be used for filtering
  159. if (!editorIsComposing) {
  160. this._refilterCompletionItems();
  161. }
  162. }));
  163. this._updateTriggerCharacters();
  164. }
  165. dispose() {
  166. dispose(this._triggerCharacterListener);
  167. dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerQuickSuggest]);
  168. this._toDispose.dispose();
  169. this._completionDisposables.dispose();
  170. this.cancel();
  171. }
  172. _updateTriggerCharacters() {
  173. this._triggerCharacterListener.clear();
  174. if (this._editor.getOption(83 /* EditorOption.readOnly */)
  175. || !this._editor.hasModel()
  176. || !this._editor.getOption(111 /* EditorOption.suggestOnTriggerCharacters */)) {
  177. return;
  178. }
  179. const supportsByTriggerCharacter = new Map();
  180. for (const support of this._languageFeaturesService.completionProvider.all(this._editor.getModel())) {
  181. for (const ch of support.triggerCharacters || []) {
  182. let set = supportsByTriggerCharacter.get(ch);
  183. if (!set) {
  184. set = new Set();
  185. set.add(getSnippetSuggestSupport());
  186. supportsByTriggerCharacter.set(ch, set);
  187. }
  188. set.add(support);
  189. }
  190. }
  191. const checkTriggerCharacter = (text) => {
  192. if (!canShowSuggestOnTriggerCharacters(this._editor, this._contextKeyService, this._configurationService)) {
  193. return;
  194. }
  195. if (LineContext.shouldAutoTrigger(this._editor)) {
  196. // don't trigger by trigger characters when this is a case for quick suggest
  197. return;
  198. }
  199. if (!text) {
  200. // came here from the compositionEnd-event
  201. const position = this._editor.getPosition();
  202. const model = this._editor.getModel();
  203. text = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
  204. }
  205. let lastChar = '';
  206. if (isLowSurrogate(text.charCodeAt(text.length - 1))) {
  207. if (isHighSurrogate(text.charCodeAt(text.length - 2))) {
  208. lastChar = text.substr(text.length - 2);
  209. }
  210. }
  211. else {
  212. lastChar = text.charAt(text.length - 1);
  213. }
  214. const supports = supportsByTriggerCharacter.get(lastChar);
  215. if (supports) {
  216. // keep existing items that where not computed by the
  217. // supports/providers that want to trigger now
  218. const existing = this._completionModel
  219. ? { items: this._completionModel.adopt(supports), clipboardText: this._completionModel.clipboardText }
  220. : undefined;
  221. this.trigger({ auto: true, shy: false, noSelect: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, existing);
  222. }
  223. };
  224. this._triggerCharacterListener.add(this._editor.onDidType(checkTriggerCharacter));
  225. this._triggerCharacterListener.add(this._editor.onDidCompositionEnd(() => checkTriggerCharacter()));
  226. }
  227. // --- trigger/retrigger/cancel suggest
  228. get state() {
  229. return this._state;
  230. }
  231. cancel(retrigger = false) {
  232. var _a;
  233. if (this._state !== 0 /* State.Idle */) {
  234. this._triggerQuickSuggest.cancel();
  235. (_a = this._requestToken) === null || _a === void 0 ? void 0 : _a.cancel();
  236. this._requestToken = undefined;
  237. this._state = 0 /* State.Idle */;
  238. this._completionModel = undefined;
  239. this._context = undefined;
  240. this._onDidCancel.fire({ retrigger });
  241. }
  242. }
  243. clear() {
  244. this._completionDisposables.clear();
  245. }
  246. _updateActiveSuggestSession() {
  247. if (this._state !== 0 /* State.Idle */) {
  248. if (!this._editor.hasModel() || !this._languageFeaturesService.completionProvider.has(this._editor.getModel())) {
  249. this.cancel();
  250. }
  251. else {
  252. this.trigger({ auto: this._state === 2 /* State.Auto */, shy: false, noSelect: false }, true);
  253. }
  254. }
  255. }
  256. _onCursorChange(e) {
  257. if (!this._editor.hasModel()) {
  258. return;
  259. }
  260. const prevSelection = this._currentSelection;
  261. this._currentSelection = this._editor.getSelection();
  262. if (!e.selection.isEmpty()
  263. || (e.reason !== 0 /* CursorChangeReason.NotSet */ && e.reason !== 3 /* CursorChangeReason.Explicit */)
  264. || (e.source !== 'keyboard' && e.source !== 'deleteLeft')) {
  265. // Early exit if nothing needs to be done!
  266. // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
  267. this.cancel();
  268. return;
  269. }
  270. if (this._state === 0 /* State.Idle */ && e.reason === 0 /* CursorChangeReason.NotSet */) {
  271. if (prevSelection.containsRange(this._currentSelection) || prevSelection.getEndPosition().isBeforeOrEqual(this._currentSelection.getPosition())) {
  272. // cursor did move RIGHT due to typing -> trigger quick suggest
  273. this._doTriggerQuickSuggest();
  274. }
  275. }
  276. else if (this._state !== 0 /* State.Idle */ && e.reason === 3 /* CursorChangeReason.Explicit */) {
  277. // suggest is active and something like cursor keys are used to move
  278. // the cursor. this means we can refilter at the new position
  279. this._refilterCompletionItems();
  280. }
  281. }
  282. _onCompositionEnd() {
  283. // trigger or refilter when composition ends
  284. if (this._state === 0 /* State.Idle */) {
  285. this._doTriggerQuickSuggest();
  286. }
  287. else {
  288. this._refilterCompletionItems();
  289. }
  290. }
  291. _doTriggerQuickSuggest() {
  292. var _a;
  293. if (QuickSuggestionsOptions.isAllOff(this._editor.getOption(81 /* EditorOption.quickSuggestions */))) {
  294. // not enabled
  295. return;
  296. }
  297. if (this._editor.getOption(108 /* EditorOption.suggest */).snippetsPreventQuickSuggestions && ((_a = SnippetController2.get(this._editor)) === null || _a === void 0 ? void 0 : _a.isInSnippet())) {
  298. // no quick suggestion when in snippet mode
  299. return;
  300. }
  301. this.cancel();
  302. this._triggerQuickSuggest.cancelAndSet(() => {
  303. if (this._state !== 0 /* State.Idle */) {
  304. return;
  305. }
  306. if (!LineContext.shouldAutoTrigger(this._editor)) {
  307. return;
  308. }
  309. if (!this._editor.hasModel() || !this._editor.hasWidgetFocus()) {
  310. return;
  311. }
  312. const model = this._editor.getModel();
  313. const pos = this._editor.getPosition();
  314. // validate enabled now
  315. const config = this._editor.getOption(81 /* EditorOption.quickSuggestions */);
  316. if (QuickSuggestionsOptions.isAllOff(config)) {
  317. return;
  318. }
  319. if (!QuickSuggestionsOptions.isAllOn(config)) {
  320. // Check the type of the token that triggered this
  321. model.tokenization.tokenizeIfCheap(pos.lineNumber);
  322. const lineTokens = model.tokenization.getLineTokens(pos.lineNumber);
  323. const tokenType = lineTokens.getStandardTokenType(lineTokens.findTokenIndexAtOffset(Math.max(pos.column - 1 - 1, 0)));
  324. if (QuickSuggestionsOptions.valueFor(config, tokenType) !== 'on') {
  325. return;
  326. }
  327. }
  328. if (!canShowQuickSuggest(this._editor, this._contextKeyService, this._configurationService)) {
  329. // do not trigger quick suggestions if inline suggestions are shown
  330. return;
  331. }
  332. if (!this._languageFeaturesService.completionProvider.has(model)) {
  333. return;
  334. }
  335. // we made it till here -> trigger now
  336. this.trigger({ auto: true, shy: false, noSelect: false });
  337. }, this._editor.getOption(82 /* EditorOption.quickSuggestionsDelay */));
  338. }
  339. _refilterCompletionItems() {
  340. // Re-filter suggestions. This MUST run async because filtering/scoring
  341. // uses the model content AND the cursor position. The latter is NOT
  342. // updated when the document has changed (the event which drives this method)
  343. // and therefore a little pause (next mirco task) is needed. See:
  344. // https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#25933985
  345. Promise.resolve().then(() => {
  346. if (this._state === 0 /* State.Idle */) {
  347. return;
  348. }
  349. if (!this._editor.hasModel()) {
  350. return;
  351. }
  352. const model = this._editor.getModel();
  353. const position = this._editor.getPosition();
  354. const ctx = new LineContext(model, position, this._state === 2 /* State.Auto */, false, false);
  355. this._onNewContext(ctx);
  356. });
  357. }
  358. trigger(context, retrigger = false, onlyFrom, existing, noFilter) {
  359. var _a;
  360. if (!this._editor.hasModel()) {
  361. return;
  362. }
  363. const model = this._editor.getModel();
  364. const auto = context.auto;
  365. const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect);
  366. // Cancel previous requests, change state & update UI
  367. this.cancel(retrigger);
  368. this._state = auto ? 2 /* State.Auto */ : 1 /* State.Manual */;
  369. this._onDidTrigger.fire({ auto, shy: context.shy, position: this._editor.getPosition() });
  370. // Capture context when request was sent
  371. this._context = ctx;
  372. // Build context for request
  373. let suggestCtx = { triggerKind: (_a = context.triggerKind) !== null && _a !== void 0 ? _a : 0 /* CompletionTriggerKind.Invoke */ };
  374. if (context.triggerCharacter) {
  375. suggestCtx = {
  376. triggerKind: 1 /* CompletionTriggerKind.TriggerCharacter */,
  377. triggerCharacter: context.triggerCharacter
  378. };
  379. }
  380. this._requestToken = new CancellationTokenSource();
  381. // kind filter and snippet sort rules
  382. const snippetSuggestions = this._editor.getOption(103 /* EditorOption.snippetSuggestions */);
  383. let snippetSortOrder = 1 /* SnippetSortOrder.Inline */;
  384. switch (snippetSuggestions) {
  385. case 'top':
  386. snippetSortOrder = 0 /* SnippetSortOrder.Top */;
  387. break;
  388. // ↓ that's the default anyways...
  389. // case 'inline':
  390. // snippetSortOrder = SnippetSortOrder.Inline;
  391. // break;
  392. case 'bottom':
  393. snippetSortOrder = 2 /* SnippetSortOrder.Bottom */;
  394. break;
  395. }
  396. const { itemKind: itemKindFilter, showDeprecated } = SuggestModel._createSuggestFilter(this._editor);
  397. const completionOptions = new CompletionOptions(snippetSortOrder, !noFilter ? itemKindFilter : new Set(), onlyFrom, showDeprecated);
  398. const wordDistance = WordDistance.create(this._editorWorkerService, this._editor);
  399. const completions = provideSuggestionItems(this._languageFeaturesService.completionProvider, model, this._editor.getPosition(), completionOptions, suggestCtx, this._requestToken.token);
  400. Promise.all([completions, wordDistance]).then(([completions, wordDistance]) => __awaiter(this, void 0, void 0, function* () {
  401. var _b;
  402. (_b = this._requestToken) === null || _b === void 0 ? void 0 : _b.dispose();
  403. if (!this._editor.hasModel()) {
  404. return;
  405. }
  406. let clipboardText = existing === null || existing === void 0 ? void 0 : existing.clipboardText;
  407. if (!clipboardText && completions.needsClipboard) {
  408. clipboardText = yield this._clipboardService.readText();
  409. }
  410. if (this._state === 0 /* State.Idle */) {
  411. return;
  412. }
  413. const model = this._editor.getModel();
  414. let items = completions.items;
  415. if (existing) {
  416. const cmpFn = getSuggestionComparator(snippetSortOrder);
  417. items = items.concat(existing.items).sort(cmpFn);
  418. }
  419. const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect);
  420. this._completionModel = new CompletionModel(items, this._context.column, {
  421. leadingLineContent: ctx.leadingLineContent,
  422. characterCountDelta: ctx.column - this._context.column
  423. }, wordDistance, this._editor.getOption(108 /* EditorOption.suggest */), this._editor.getOption(103 /* EditorOption.snippetSuggestions */), undefined, clipboardText);
  424. // store containers so that they can be disposed later
  425. this._completionDisposables.add(completions.disposable);
  426. this._onNewContext(ctx);
  427. // finally report telemetry about durations
  428. this._reportDurationsTelemetry(completions.durations);
  429. })).catch(onUnexpectedError);
  430. }
  431. _reportDurationsTelemetry(durations) {
  432. if (this._telemetryGate++ % 230 !== 0) {
  433. return;
  434. }
  435. setTimeout(() => {
  436. this._telemetryService.publicLog2('suggest.durations.json', { data: JSON.stringify(durations) });
  437. this._logService.debug('suggest.durations.json', durations);
  438. });
  439. }
  440. static _createSuggestFilter(editor) {
  441. // kind filter and snippet sort rules
  442. const result = new Set();
  443. // snippet setting
  444. const snippetSuggestions = editor.getOption(103 /* EditorOption.snippetSuggestions */);
  445. if (snippetSuggestions === 'none') {
  446. result.add(27 /* CompletionItemKind.Snippet */);
  447. }
  448. // type setting
  449. const suggestOptions = editor.getOption(108 /* EditorOption.suggest */);
  450. if (!suggestOptions.showMethods) {
  451. result.add(0 /* CompletionItemKind.Method */);
  452. }
  453. if (!suggestOptions.showFunctions) {
  454. result.add(1 /* CompletionItemKind.Function */);
  455. }
  456. if (!suggestOptions.showConstructors) {
  457. result.add(2 /* CompletionItemKind.Constructor */);
  458. }
  459. if (!suggestOptions.showFields) {
  460. result.add(3 /* CompletionItemKind.Field */);
  461. }
  462. if (!suggestOptions.showVariables) {
  463. result.add(4 /* CompletionItemKind.Variable */);
  464. }
  465. if (!suggestOptions.showClasses) {
  466. result.add(5 /* CompletionItemKind.Class */);
  467. }
  468. if (!suggestOptions.showStructs) {
  469. result.add(6 /* CompletionItemKind.Struct */);
  470. }
  471. if (!suggestOptions.showInterfaces) {
  472. result.add(7 /* CompletionItemKind.Interface */);
  473. }
  474. if (!suggestOptions.showModules) {
  475. result.add(8 /* CompletionItemKind.Module */);
  476. }
  477. if (!suggestOptions.showProperties) {
  478. result.add(9 /* CompletionItemKind.Property */);
  479. }
  480. if (!suggestOptions.showEvents) {
  481. result.add(10 /* CompletionItemKind.Event */);
  482. }
  483. if (!suggestOptions.showOperators) {
  484. result.add(11 /* CompletionItemKind.Operator */);
  485. }
  486. if (!suggestOptions.showUnits) {
  487. result.add(12 /* CompletionItemKind.Unit */);
  488. }
  489. if (!suggestOptions.showValues) {
  490. result.add(13 /* CompletionItemKind.Value */);
  491. }
  492. if (!suggestOptions.showConstants) {
  493. result.add(14 /* CompletionItemKind.Constant */);
  494. }
  495. if (!suggestOptions.showEnums) {
  496. result.add(15 /* CompletionItemKind.Enum */);
  497. }
  498. if (!suggestOptions.showEnumMembers) {
  499. result.add(16 /* CompletionItemKind.EnumMember */);
  500. }
  501. if (!suggestOptions.showKeywords) {
  502. result.add(17 /* CompletionItemKind.Keyword */);
  503. }
  504. if (!suggestOptions.showWords) {
  505. result.add(18 /* CompletionItemKind.Text */);
  506. }
  507. if (!suggestOptions.showColors) {
  508. result.add(19 /* CompletionItemKind.Color */);
  509. }
  510. if (!suggestOptions.showFiles) {
  511. result.add(20 /* CompletionItemKind.File */);
  512. }
  513. if (!suggestOptions.showReferences) {
  514. result.add(21 /* CompletionItemKind.Reference */);
  515. }
  516. if (!suggestOptions.showColors) {
  517. result.add(22 /* CompletionItemKind.Customcolor */);
  518. }
  519. if (!suggestOptions.showFolders) {
  520. result.add(23 /* CompletionItemKind.Folder */);
  521. }
  522. if (!suggestOptions.showTypeParameters) {
  523. result.add(24 /* CompletionItemKind.TypeParameter */);
  524. }
  525. if (!suggestOptions.showSnippets) {
  526. result.add(27 /* CompletionItemKind.Snippet */);
  527. }
  528. if (!suggestOptions.showUsers) {
  529. result.add(25 /* CompletionItemKind.User */);
  530. }
  531. if (!suggestOptions.showIssues) {
  532. result.add(26 /* CompletionItemKind.Issue */);
  533. }
  534. return { itemKind: result, showDeprecated: suggestOptions.showDeprecated };
  535. }
  536. _onNewContext(ctx) {
  537. if (!this._context) {
  538. // happens when 24x7 IntelliSense is enabled and still in its delay
  539. return;
  540. }
  541. if (ctx.lineNumber !== this._context.lineNumber) {
  542. // e.g. happens when pressing Enter while IntelliSense is computed
  543. this.cancel();
  544. return;
  545. }
  546. if (getLeadingWhitespace(ctx.leadingLineContent) !== getLeadingWhitespace(this._context.leadingLineContent)) {
  547. // cancel IntelliSense when line start changes
  548. // happens when the current word gets outdented
  549. this.cancel();
  550. return;
  551. }
  552. if (ctx.column < this._context.column) {
  553. // typed -> moved cursor LEFT -> retrigger if still on a word
  554. if (ctx.leadingWord.word) {
  555. this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true);
  556. }
  557. else {
  558. this.cancel();
  559. }
  560. return;
  561. }
  562. if (!this._completionModel) {
  563. // happens when IntelliSense is not yet computed
  564. return;
  565. }
  566. if (ctx.leadingWord.word.length !== 0 && ctx.leadingWord.startColumn > this._context.leadingWord.startColumn) {
  567. // started a new word while IntelliSense shows -> retrigger
  568. // Select those providers have not contributed to this completion model and re-trigger completions for
  569. // them. Also adopt the existing items and merge them into the new completion model
  570. const inactiveProvider = new Set(this._languageFeaturesService.completionProvider.all(this._editor.getModel()));
  571. for (const provider of this._completionModel.allProvider) {
  572. inactiveProvider.delete(provider);
  573. }
  574. const items = this._completionModel.adopt(new Set());
  575. this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true, inactiveProvider, { items, clipboardText: this._completionModel.clipboardText });
  576. return;
  577. }
  578. if (ctx.column > this._context.column && this._completionModel.incomplete.size > 0 && ctx.leadingWord.word.length !== 0) {
  579. // typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger
  580. const { incomplete } = this._completionModel;
  581. const items = this._completionModel.adopt(incomplete);
  582. this.trigger({ auto: this._state === 2 /* State.Auto */, shy: false, noSelect: false, triggerKind: 2 /* CompletionTriggerKind.TriggerForIncompleteCompletions */ }, true, incomplete, { items, clipboardText: this._completionModel.clipboardText });
  583. }
  584. else {
  585. // typed -> moved cursor RIGHT -> update UI
  586. const oldLineContext = this._completionModel.lineContext;
  587. let isFrozen = false;
  588. this._completionModel.lineContext = {
  589. leadingLineContent: ctx.leadingLineContent,
  590. characterCountDelta: ctx.column - this._context.column
  591. };
  592. if (this._completionModel.items.length === 0) {
  593. if (LineContext.shouldAutoTrigger(this._editor) && this._context.leadingWord.endColumn < ctx.leadingWord.startColumn) {
  594. // retrigger when heading into a new word
  595. this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true);
  596. return;
  597. }
  598. if (!this._context.auto) {
  599. // freeze when IntelliSense was manually requested
  600. this._completionModel.lineContext = oldLineContext;
  601. isFrozen = this._completionModel.items.length > 0;
  602. if (isFrozen && ctx.leadingWord.word.length === 0) {
  603. // there were results before but now there aren't
  604. // and also we are not on a word anymore -> cancel
  605. this.cancel();
  606. return;
  607. }
  608. }
  609. else {
  610. // nothing left
  611. this.cancel();
  612. return;
  613. }
  614. }
  615. this._onDidSuggest.fire({
  616. completionModel: this._completionModel,
  617. auto: this._context.auto,
  618. shy: this._context.shy,
  619. noSelect: this._context.noSelect,
  620. isFrozen,
  621. });
  622. }
  623. }
  624. };
  625. SuggestModel = __decorate([
  626. __param(1, IEditorWorkerService),
  627. __param(2, IClipboardService),
  628. __param(3, ITelemetryService),
  629. __param(4, ILogService),
  630. __param(5, IContextKeyService),
  631. __param(6, IConfigurationService),
  632. __param(7, ILanguageFeaturesService)
  633. ], SuggestModel);
  634. export { SuggestModel };