提交 ef88842d 编写于 作者: J Johannes Rieken

completion model isn't dispoable but the suggest model that requests items, #75106

上级 466b29a0
......@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore, anyScore } from 'vs/base/common/filters';
import { isDisposable } from 'vs/base/common/lifecycle';
import { CompletionList, CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes';
import { CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes';
import { CompletionItem } from './suggest';
import { InternalSuggestOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance';
......@@ -75,18 +74,6 @@ export class CompletionModel {
}
}
dispose(): void {
const seen = new Set<CompletionList>();
for (const { container } of this._items) {
if (!seen.has(container)) {
seen.add(container);
if (isDisposable(container)) {
container.dispose();
}
}
}
}
get lineContext(): LineContext {
return this._lineContext;
}
......
......@@ -135,6 +135,7 @@ export class SuggestController implements IEditorContribution {
this._toDispose.push(this._editor.onDidBlurEditorWidget(() => {
if (!this._sticky) {
this._model.cancel();
this._model.clear();
}
}));
......@@ -165,6 +166,7 @@ export class SuggestController implements IEditorContribution {
if (!event || !event.item) {
this._alternatives.getValue().reset();
this._model.cancel();
this._model.clear();
return;
}
if (!this._editor.hasModel()) {
......@@ -213,6 +215,7 @@ export class SuggestController implements IEditorContribution {
if (!suggestion.command) {
// done
this._model.cancel();
this._model.clear();
} else if (suggestion.command.id === TriggerSuggestAction.id) {
// retigger
......@@ -220,7 +223,9 @@ export class SuggestController implements IEditorContribution {
} else {
// exec command, done
this._commandService.executeCommand(suggestion.command.id, ...(suggestion.command.arguments ? [...suggestion.command.arguments] : [])).catch(onUnexpectedError);
this._commandService.executeCommand(suggestion.command.id, ...(suggestion.command.arguments ? [...suggestion.command.arguments] : []))
.catch(onUnexpectedError)
.finally(() => this._model.clear()); // <- clear only now, keep commands alive
this._model.cancel();
}
......@@ -340,6 +345,7 @@ export class SuggestController implements IEditorContribution {
cancelSuggestWidget(): void {
this._model.cancel();
this._model.clear();
this._widget.getValue().hideWidget();
}
......
......@@ -7,7 +7,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { TimeoutTimer } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, DisposableStore, isDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { Position } from 'vs/editor/common/core/position';
......@@ -101,7 +101,8 @@ export class SuggestModel implements IDisposable {
private _context?: LineContext;
private _currentSelection: Selection;
private readonly _completionModel = new MutableDisposable<CompletionModel>();
private _completionModel: CompletionModel | undefined;
private readonly _completionDisposables = new DisposableStore();
private readonly _onDidCancel = new Emitter<ICancelEvent>();
private readonly _onDidTrigger = new Emitter<ITriggerEvent>();
private readonly _onDidSuggest = new Emitter<ISuggestEvent>();
......@@ -162,7 +163,7 @@ export class SuggestModel implements IDisposable {
dispose(): void {
dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerQuickSuggest]);
this._toDispose.dispose();
this._completionModel.dispose();
this._completionDisposables.dispose();
this.cancel();
}
......@@ -206,8 +207,8 @@ export class SuggestModel implements IDisposable {
if (supports) {
// keep existing items that where not computed by the
// supports/providers that want to trigger now
const items: CompletionItem[] | undefined = this._completionModel.value ? this._completionModel.value.adopt(supports) : undefined;
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel.value), supports, items);
const items: CompletionItem[] | undefined = this._completionModel ? this._completionModel.adopt(supports) : undefined;
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, items);
}
});
}
......@@ -226,12 +227,16 @@ export class SuggestModel implements IDisposable {
this._requestToken = undefined;
}
this._state = State.Idle;
this._completionModel.clear();
this._completionModel = undefined;
this._context = undefined;
this._onDidCancel.fire({ retrigger });
}
}
clear() {
this._completionDisposables.clear();
}
private _updateActiveSuggestSession(): void {
if (this._state !== State.Idle) {
if (!this._editor.hasModel() || !CompletionProviderRegistry.has(this._editor.getModel())) {
......@@ -434,13 +439,21 @@ export class SuggestModel implements IDisposable {
}
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy);
this._completionModel.value = new CompletionModel(items, this._context!.column, {
this._completionModel = new CompletionModel(items, this._context!.column, {
leadingLineContent: ctx.leadingLineContent,
characterCountDelta: ctx.column - this._context!.column
},
wordDistance,
this._editor.getConfiguration().contribInfo.suggest
);
// store containers so that they can be disposed later
for (const item of items) {
if (isDisposable(item.container)) {
this._completionDisposables.add(item.container);
}
}
this._onNewContext(ctx);
}).catch(onUnexpectedError);
......@@ -475,28 +488,28 @@ export class SuggestModel implements IDisposable {
return;
}
if (!this._completionModel.value) {
if (!this._completionModel) {
// happens when IntelliSense is not yet computed
return;
}
if (ctx.column > this._context.column && this._completionModel.value.incomplete.size > 0 && ctx.leadingWord.word.length !== 0) {
if (ctx.column > this._context.column && this._completionModel.incomplete.size > 0 && ctx.leadingWord.word.length !== 0) {
// typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger
const { incomplete } = this._completionModel.value;
const adopted = this._completionModel.value.adopt(incomplete);
const { incomplete } = this._completionModel;
const adopted = this._completionModel.adopt(incomplete);
this.trigger({ auto: this._state === State.Auto, shy: false }, true, incomplete, adopted);
} else {
// typed -> moved cursor RIGHT -> update UI
let oldLineContext = this._completionModel.value.lineContext;
let oldLineContext = this._completionModel.lineContext;
let isFrozen = false;
this._completionModel.value.lineContext = {
this._completionModel.lineContext = {
leadingLineContent: ctx.leadingLineContent,
characterCountDelta: ctx.column - this._context.column
};
if (this._completionModel.value.items.length === 0) {
if (this._completionModel.items.length === 0) {
if (LineContext.shouldAutoTrigger(this._editor) && this._context.leadingWord.endColumn < ctx.leadingWord.startColumn) {
// retrigger when heading into a new word
......@@ -506,8 +519,8 @@ export class SuggestModel implements IDisposable {
if (!this._context.auto) {
// freeze when IntelliSense was manually requested
this._completionModel.value.lineContext = oldLineContext;
isFrozen = this._completionModel.value.items.length > 0;
this._completionModel.lineContext = oldLineContext;
isFrozen = this._completionModel.items.length > 0;
if (isFrozen && ctx.leadingWord.word.length === 0) {
// there were results before but now there aren't
......@@ -524,7 +537,7 @@ export class SuggestModel implements IDisposable {
}
this._onDidSuggest.fire({
completionModel: this._completionModel.value,
completionModel: this._completionModel,
auto: this._context.auto,
shy: this._context.shy,
isFrozen,
......
......@@ -221,6 +221,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
try {
action();
} catch (err) {
sub.dispose();
reject(err);
}
});
......@@ -776,9 +777,13 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
}, event => {
assert.equal(event.auto, true);
assert.equal(event.completionModel.items.length, 2);
assert.equal(disposeA, 1);
assert.equal(disposeB, 0);
// clean up
model.clear();
assert.equal(disposeA, 2); // provide got called two times!
assert.equal(disposeB, 1);
});
});
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册