mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 8aa90d444f5d051984e8055f547c4252d53479b3 (#5587)
* Merge from vscode 8aa90d444f5d051984e8055f547c4252d53479b3 * pipeline errors * fix build
This commit is contained in:
@@ -10,6 +10,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { EditorKeybindingCancellationTokenSource } from 'vs/editor/browser/core/keybindingCancellation';
|
||||
|
||||
export const enum CodeEditorStateFlag {
|
||||
Value = 1,
|
||||
@@ -78,12 +79,12 @@ export class EditorState {
|
||||
* A cancellation token source that cancels when the editor changes as expressed
|
||||
* by the provided flags
|
||||
*/
|
||||
export class EditorStateCancellationTokenSource extends CancellationTokenSource {
|
||||
export class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource {
|
||||
|
||||
private readonly _listener: IDisposable[] = [];
|
||||
|
||||
constructor(readonly editor: IActiveCodeEditor, flags: CodeEditorStateFlag, parent?: CancellationToken) {
|
||||
super(parent);
|
||||
super(editor, parent);
|
||||
|
||||
if (flags & CodeEditorStateFlag.Position) {
|
||||
this._listener.push(editor.onDidChangeCursorPosition(_ => this.cancel()));
|
||||
|
||||
105
src/vs/editor/browser/core/keybindingCancellation.ts
Normal file
105
src/vs/editor/browser/core/keybindingCancellation.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
|
||||
const IEditorCancellationTokens = createDecorator<IEditorCancellationTokens>('IEditorCancelService');
|
||||
|
||||
interface IEditorCancellationTokens {
|
||||
_serviceBrand: any;
|
||||
add(editor: ICodeEditor, cts: CancellationTokenSource): () => void;
|
||||
cancel(editor: ICodeEditor): void;
|
||||
}
|
||||
|
||||
const ctxCancellableOperation = new RawContextKey('cancellableOperation', false);
|
||||
|
||||
registerSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly _tokens = new WeakMap<ICodeEditor, { key: IContextKey<boolean>, tokens: LinkedList<CancellationTokenSource> }>();
|
||||
|
||||
add(editor: ICodeEditor, cts: CancellationTokenSource): () => void {
|
||||
let data = this._tokens.get(editor);
|
||||
if (!data) {
|
||||
data = editor.invokeWithinContext(accessor => {
|
||||
const key = ctxCancellableOperation.bindTo(accessor.get(IContextKeyService));
|
||||
const tokens = new LinkedList<CancellationTokenSource>();
|
||||
return { key, tokens };
|
||||
});
|
||||
this._tokens.set(editor, data);
|
||||
}
|
||||
|
||||
let removeFn: Function | undefined;
|
||||
|
||||
data.key.set(true);
|
||||
removeFn = data.tokens.push(cts);
|
||||
|
||||
return () => {
|
||||
// remove w/o cancellation
|
||||
if (removeFn) {
|
||||
removeFn();
|
||||
data!.key.set(!data!.tokens.isEmpty());
|
||||
removeFn = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cancel(editor: ICodeEditor): void {
|
||||
const data = this._tokens.get(editor);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
// remove with cancellation
|
||||
const cts = data.tokens.pop();
|
||||
if (cts) {
|
||||
cts.cancel();
|
||||
data.key.set(!data.tokens.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
}, true);
|
||||
|
||||
export class EditorKeybindingCancellationTokenSource extends CancellationTokenSource {
|
||||
|
||||
private readonly _unregister: Function;
|
||||
|
||||
constructor(readonly editor: ICodeEditor, parent?: CancellationToken) {
|
||||
super(parent);
|
||||
this._unregister = editor.invokeWithinContext(accessor => accessor.get(IEditorCancellationTokens).add(editor, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._unregister();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorCommand(new class extends EditorCommand {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.cancelOperation',
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorContrib,
|
||||
primary: KeyCode.Escape
|
||||
},
|
||||
precondition: ctxCancellableOperation
|
||||
});
|
||||
}
|
||||
|
||||
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
accessor.get(IEditorCancellationTokens).cancel(editor);
|
||||
}
|
||||
});
|
||||
@@ -323,9 +323,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
|
||||
if (this._renderSideBySide) {
|
||||
this._setStrategy(new DiffEdtorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
|
||||
this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
|
||||
} else {
|
||||
this._setStrategy(new DiffEdtorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
|
||||
this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
|
||||
}
|
||||
|
||||
this._register(themeService.onThemeChange(t => {
|
||||
@@ -597,9 +597,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
// renderSideBySide
|
||||
if (renderSideBySideChanged) {
|
||||
if (this._renderSideBySide) {
|
||||
this._setStrategy(new DiffEdtorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
|
||||
this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
|
||||
} else {
|
||||
this._setStrategy(new DiffEdtorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
|
||||
this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
|
||||
}
|
||||
// Update class name
|
||||
this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide);
|
||||
@@ -1547,7 +1547,7 @@ const DECORATIONS = {
|
||||
|
||||
};
|
||||
|
||||
class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider {
|
||||
class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider {
|
||||
|
||||
static MINIMUM_EDITOR_WIDTH = 100;
|
||||
|
||||
@@ -1592,13 +1592,13 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
|
||||
|
||||
sashPosition = this._disableSash ? midPoint : sashPosition || midPoint;
|
||||
|
||||
if (contentWidth > DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) {
|
||||
if (sashPosition < DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
|
||||
sashPosition = DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
|
||||
if (contentWidth > DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) {
|
||||
if (sashPosition < DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
|
||||
sashPosition = DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
|
||||
}
|
||||
|
||||
if (sashPosition > contentWidth - DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
|
||||
sashPosition = contentWidth - DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
|
||||
if (sashPosition > contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
|
||||
sashPosition = contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
|
||||
}
|
||||
} else {
|
||||
sashPosition = midPoint;
|
||||
@@ -1807,7 +1807,7 @@ class SideBySideViewZonesComputer extends ViewZonesComputer {
|
||||
}
|
||||
}
|
||||
|
||||
class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle {
|
||||
class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle {
|
||||
|
||||
private decorationsLeft: number;
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ class EditorModelManager extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public esureSyncedResources(resources: URI[]): void {
|
||||
public ensureSyncedResources(resources: URI[]): void {
|
||||
for (const resource of resources) {
|
||||
let resourceStr = resource.toString();
|
||||
|
||||
@@ -387,7 +387,7 @@ export class EditorWorkerClient extends Disposable {
|
||||
|
||||
protected _withSyncedResources(resources: URI[]): Promise<EditorSimpleWorkerImpl> {
|
||||
return this._getProxy().then((proxy) => {
|
||||
this._getOrCreateModelManager(proxy).esureSyncedResources(resources);
|
||||
this._getOrCreateModelManager(proxy).ensureSyncedResources(resources);
|
||||
return proxy;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CodeEditorStateFlag, EditorState, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState';
|
||||
import { CodeEditorStateFlag, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState';
|
||||
import { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerLanguageCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -143,27 +143,25 @@ export async function formatDocumentRangeWithProvider(
|
||||
const workerService = accessor.get(IEditorWorkerService);
|
||||
|
||||
let model: ITextModel;
|
||||
let validate: () => boolean;
|
||||
let cts: CancellationTokenSource;
|
||||
if (isCodeEditor(editorOrModel)) {
|
||||
model = editorOrModel.getModel();
|
||||
const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
|
||||
validate = () => state.validate(editorOrModel);
|
||||
cts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, token);
|
||||
} else {
|
||||
model = editorOrModel;
|
||||
const versionNow = editorOrModel.getVersionId();
|
||||
validate = () => versionNow === editorOrModel.getVersionId();
|
||||
cts = new TextModelCancellationTokenSource(editorOrModel, token);
|
||||
}
|
||||
|
||||
const rawEdits = await provider.provideDocumentRangeFormattingEdits(
|
||||
model,
|
||||
range,
|
||||
model.getFormattingOptions(),
|
||||
token
|
||||
cts.token
|
||||
);
|
||||
|
||||
const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
|
||||
|
||||
if (!validate()) {
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { createCancelablePromise } from 'vs/base/common/async';
|
||||
import { createCancelablePromise, raceCancellation } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
@@ -64,9 +64,9 @@ export class DefinitionAction extends EditorAction {
|
||||
|
||||
const cts = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
|
||||
|
||||
const definitionPromise = this._getTargetLocationForPosition(model, pos, cts.token).then(async references => {
|
||||
const definitionPromise = raceCancellation(this._getTargetLocationForPosition(model, pos, cts.token), cts.token).then(async references => {
|
||||
|
||||
if (cts.token.isCancellationRequested || model.isDisposed() || editor.getModel() !== model) {
|
||||
if (!references || model.isDisposed()) {
|
||||
// new model, no more model
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { fuzzyScore, fuzzyScoreGracefulAggressive, anyScore, FuzzyScorer, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { isDisposable } from 'vs/base/common/lifecycle';
|
||||
import { CompletionList, 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';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { compareIgnoreCase } from 'vs/base/common/strings';
|
||||
|
||||
type StrictCompletionItem = Required<CompletionItem>;
|
||||
|
||||
@@ -215,8 +216,15 @@ export class CompletionModel {
|
||||
if (!match) {
|
||||
continue; // NO match
|
||||
}
|
||||
item.score = anyScore(word, wordLow, 0, item.completion.label, item.labelLow, 0);
|
||||
item.score[0] = match[0]; // use score from filterText
|
||||
if (compareIgnoreCase(item.completion.filterText, item.completion.label) === 0) {
|
||||
// filterText and label are actually the same -> use good highlights
|
||||
item.score = match;
|
||||
} else {
|
||||
// re-run the scorer on the label in the hope of a result BUT use the rank
|
||||
// of the filterText-match
|
||||
item.score = scoreFn(word, wordLow, wordPos, item.completion.label, item.labelLow, 0, false) || FuzzyScore.Default;
|
||||
item.score[0] = match[0]; // use score from filterText
|
||||
}
|
||||
|
||||
} else {
|
||||
// by default match `word` against the `label`
|
||||
|
||||
59
src/vs/editor/contrib/suggest/suggestCommitCharacters.ts
Normal file
59
src/vs/editor/contrib/suggest/suggestCommitCharacters.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ISelectedSuggestion, SuggestWidget } from './suggestWidget';
|
||||
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
|
||||
|
||||
export class CommitCharacterController {
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _active?: {
|
||||
readonly acceptCharacters: CharacterSet;
|
||||
readonly item: ISelectedSuggestion;
|
||||
};
|
||||
|
||||
constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) {
|
||||
|
||||
this._disposables.push(widget.onDidShow(() => this._onItem(widget.getFocusedItem())));
|
||||
this._disposables.push(widget.onDidFocus(this._onItem, this));
|
||||
this._disposables.push(widget.onDidHide(this.reset, this));
|
||||
|
||||
this._disposables.push(editor.onWillType(text => {
|
||||
if (this._active) {
|
||||
const ch = text.charCodeAt(text.length - 1);
|
||||
if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) {
|
||||
accept(this._active.item);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _onItem(selected: ISelectedSuggestion | undefined): void {
|
||||
if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const acceptCharacters = new CharacterSet();
|
||||
for (const ch of selected.item.completion.commitCharacters) {
|
||||
if (ch.length > 0) {
|
||||
acceptCharacters.add(ch.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
this._active = { acceptCharacters, item: selected };
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._active = undefined;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(this._disposables);
|
||||
}
|
||||
}
|
||||
@@ -31,57 +31,8 @@ import { WordContextKey } from 'vs/editor/contrib/suggest/wordContextKey';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
|
||||
class AcceptOnCharacterOracle {
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _active?: {
|
||||
readonly acceptCharacters: CharacterSet;
|
||||
readonly item: ISelectedSuggestion;
|
||||
};
|
||||
|
||||
constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) {
|
||||
|
||||
this._disposables.push(widget.onDidShow(() => this._onItem(widget.getFocusedItem())));
|
||||
this._disposables.push(widget.onDidFocus(this._onItem, this));
|
||||
this._disposables.push(widget.onDidHide(this.reset, this));
|
||||
|
||||
this._disposables.push(editor.onWillType(text => {
|
||||
if (this._active) {
|
||||
const ch = text.charCodeAt(text.length - 1);
|
||||
if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) {
|
||||
accept(this._active.item);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _onItem(selected: ISelectedSuggestion | undefined): void {
|
||||
if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const acceptCharacters = new CharacterSet();
|
||||
for (const ch of selected.item.completion.commitCharacters) {
|
||||
if (ch.length > 0) {
|
||||
acceptCharacters.add(ch.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
this._active = { acceptCharacters, item: selected };
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._active = undefined;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(this._disposables);
|
||||
}
|
||||
}
|
||||
import { CommitCharacterController } from './suggestCommitCharacters';
|
||||
|
||||
export class SuggestController implements IEditorContribution {
|
||||
|
||||
@@ -113,15 +64,15 @@ export class SuggestController implements IEditorContribution {
|
||||
const widget = this._instantiationService.createInstance(SuggestWidget, this._editor);
|
||||
|
||||
this._toDispose.push(widget);
|
||||
this._toDispose.push(widget.onDidSelect(item => this._onDidSelectItem(item, false, true), this));
|
||||
this._toDispose.push(widget.onDidSelect(item => this._insertSuggestion(item, false, true), this));
|
||||
|
||||
// Wire up logic to accept a suggestion on certain characters
|
||||
const autoAcceptOracle = new AcceptOnCharacterOracle(this._editor, widget, item => this._onDidSelectItem(item, false, true));
|
||||
const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true));
|
||||
this._toDispose.push(
|
||||
autoAcceptOracle,
|
||||
commitCharacterController,
|
||||
this._model.onDidSuggest(e => {
|
||||
if (e.completionModel.items.length === 0) {
|
||||
autoAcceptOracle.reset();
|
||||
commitCharacterController.reset();
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -210,7 +161,7 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
}
|
||||
|
||||
protected _onDidSelectItem(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStops: boolean): void {
|
||||
protected _insertSuggestion(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStops: boolean): void {
|
||||
if (!event || !event.item) {
|
||||
this._alternatives.getValue().reset();
|
||||
this._model.cancel();
|
||||
@@ -282,7 +233,7 @@ export class SuggestController implements IEditorContribution {
|
||||
if (modelVersionNow !== model.getAlternativeVersionId()) {
|
||||
model.undo();
|
||||
}
|
||||
this._onDidSelectItem(next, false, false);
|
||||
this._insertSuggestion(next, false, false);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -364,7 +315,7 @@ export class SuggestController implements IEditorContribution {
|
||||
return;
|
||||
}
|
||||
this._editor.pushUndoStop();
|
||||
this._onDidSelectItem({ index, item, model: completionModel }, true, false);
|
||||
this._insertSuggestion({ index, item, model: completionModel }, true, false);
|
||||
|
||||
}, undefined, listener);
|
||||
});
|
||||
@@ -375,10 +326,8 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
|
||||
acceptSelectedSuggestion(keepAlternativeSuggestions?: boolean): void {
|
||||
if (this._widget) {
|
||||
const item = this._widget.getValue().getFocusedItem();
|
||||
this._onDidSelectItem(item, !!keepAlternativeSuggestions, true);
|
||||
}
|
||||
const item = this._widget.getValue().getFocusedItem();
|
||||
this._insertSuggestion(item, !!keepAlternativeSuggestions, true);
|
||||
}
|
||||
|
||||
acceptNextSuggestion() {
|
||||
@@ -390,58 +339,40 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
|
||||
cancelSuggestWidget(): void {
|
||||
if (this._widget) {
|
||||
this._model.cancel();
|
||||
this._widget.getValue().hideWidget();
|
||||
}
|
||||
this._model.cancel();
|
||||
this._widget.getValue().hideWidget();
|
||||
}
|
||||
|
||||
selectNextSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectNext();
|
||||
}
|
||||
this._widget.getValue().selectNext();
|
||||
}
|
||||
|
||||
selectNextPageSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectNextPage();
|
||||
}
|
||||
this._widget.getValue().selectNextPage();
|
||||
}
|
||||
|
||||
selectLastSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectLast();
|
||||
}
|
||||
this._widget.getValue().selectLast();
|
||||
}
|
||||
|
||||
selectPrevSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectPrevious();
|
||||
}
|
||||
this._widget.getValue().selectPrevious();
|
||||
}
|
||||
|
||||
selectPrevPageSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectPreviousPage();
|
||||
}
|
||||
this._widget.getValue().selectPreviousPage();
|
||||
}
|
||||
|
||||
selectFirstSuggestion(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().selectFirst();
|
||||
}
|
||||
this._widget.getValue().selectFirst();
|
||||
}
|
||||
|
||||
toggleSuggestionDetails(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().toggleDetails();
|
||||
}
|
||||
this._widget.getValue().toggleDetails();
|
||||
}
|
||||
|
||||
toggleSuggestionFocus(): void {
|
||||
if (this._widget) {
|
||||
this._widget.getValue().toggleDetailsFocus();
|
||||
}
|
||||
this._widget.getValue().toggleDetailsFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@ export class SuggestModel implements IDisposable {
|
||||
private _quickSuggestDelay: number;
|
||||
private _triggerCharacterListener: IDisposable;
|
||||
private readonly _triggerQuickSuggest = new TimeoutTimer();
|
||||
private readonly _triggerRefilter = new TimeoutTimer();
|
||||
private _state: State = State.Idle;
|
||||
|
||||
private _requestToken?: CancellationTokenSource;
|
||||
@@ -161,7 +160,7 @@ export class SuggestModel implements IDisposable {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerQuickSuggest, this._triggerRefilter]);
|
||||
dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerQuickSuggest]);
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
dispose(this._completionModel);
|
||||
this.cancel();
|
||||
@@ -221,7 +220,6 @@ export class SuggestModel implements IDisposable {
|
||||
|
||||
cancel(retrigger: boolean = false): void {
|
||||
if (this._state !== State.Idle) {
|
||||
this._triggerRefilter.cancel();
|
||||
this._triggerQuickSuggest.cancel();
|
||||
if (this._requestToken) {
|
||||
this._requestToken.cancel();
|
||||
@@ -328,14 +326,15 @@ export class SuggestModel implements IDisposable {
|
||||
}
|
||||
|
||||
private _refilterCompletionItems(): void {
|
||||
if (this._state === State.Idle) {
|
||||
return;
|
||||
}
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
// refine active suggestion
|
||||
this._triggerRefilter.cancelAndSet(() => {
|
||||
// Re-filter suggestions. This MUST run async because filtering/scoring
|
||||
// uses the model content AND the cursor position. The latter is NOT
|
||||
// updated when the document has changed (the event which drives this method)
|
||||
// and therefore a little pause (next mirco task) is needed. See:
|
||||
// https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#25933985
|
||||
Promise.resolve().then(() => {
|
||||
if (this._state === State.Idle) {
|
||||
return;
|
||||
}
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
@@ -343,7 +342,7 @@ export class SuggestModel implements IDisposable {
|
||||
const position = this._editor.getPosition();
|
||||
const ctx = new LineContext(model, position, this._state === State.Auto, false);
|
||||
this._onNewContext(ctx);
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set<CompletionItemProvider>, existingItems?: CompletionItem[]): void {
|
||||
|
||||
@@ -30,7 +30,6 @@ import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { TimeoutTimer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CompletionItemKind, completionKindToCssClass } from 'vs/editor/common/modes';
|
||||
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
|
||||
@@ -545,10 +544,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
return;
|
||||
}
|
||||
|
||||
item.resolve(CancellationToken.None).then(() => {
|
||||
this.onDidSelectEmitter.fire({ item, index, model: completionModel });
|
||||
this.editor.focus();
|
||||
});
|
||||
this.onDidSelectEmitter.fire({ item, index, model: completionModel });
|
||||
this.editor.focus();
|
||||
}
|
||||
|
||||
private _getSuggestionAriaAlertLabel(item: CompletionItem): string {
|
||||
|
||||
@@ -671,8 +671,8 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
|
||||
|
||||
return withOracle(async (sugget, editor) => {
|
||||
class TestCtrl extends SuggestController {
|
||||
_onDidSelectItem(item: ISelectedSuggestion) {
|
||||
super._onDidSelectItem(item, false, true);
|
||||
_insertSuggestion(item: ISelectedSuggestion) {
|
||||
super._insertSuggestion(item, false, true);
|
||||
}
|
||||
}
|
||||
const ctrl = <TestCtrl>editor.registerAndInstantiateContribution(TestCtrl);
|
||||
@@ -687,7 +687,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
|
||||
const [first] = event.completionModel.items;
|
||||
assert.equal(first.completion.label, 'bar');
|
||||
|
||||
ctrl._onDidSelectItem({ item: first, index: 0, model: event.completionModel });
|
||||
ctrl._insertSuggestion({ item: first, index: 0, model: event.completionModel });
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
|
||||
Reference in New Issue
Block a user