diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 3479f9d98fd..c052ad69b6b 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -297,7 +297,7 @@ export enum SubstringMatching { Separate } -const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString); +export const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString); const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString); const fuzzyRegExpCache: { [key: string]: RegExp; } = {}; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index d3bcc1231d2..4e4c8aad6fe 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IMatch} from 'vs/base/common/filters'; import {IHTMLContentElement} from 'vs/base/common/htmlContent'; import {IDisposable} from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; +import {IFilter} from 'vs/base/common/filters'; import {IMarker} from 'vs/platform/markers/common/markers'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; @@ -365,11 +365,6 @@ export interface ISuggestResult { incomplete?: boolean; } -export interface ISuggestionFilter { - // Should return whether `suggestion` is a good suggestion for `word` - (word: string, suggestion: ISuggestion): IMatch[]; -} - /** * Interface used to get completion suggestions at a specific location. */ @@ -385,7 +380,7 @@ export interface ISuggestSupport { */ getSuggestionDetails?: (resource: URI, position: editorCommon.IPosition, suggestion: ISuggestion) => TPromise; - getFilter(): ISuggestionFilter; + filter?: IFilter; getTriggerCharacters(): string[]; shouldShowEmptySuggestionList(): boolean; shouldAutotriggerSuggest(context: ILineContext, offset: number, triggeredByCharacter: string): boolean; diff --git a/src/vs/editor/common/modes/modesFilters.ts b/src/vs/editor/common/modes/modesFilters.ts deleted file mode 100644 index 0941b549cf8..00000000000 --- a/src/vs/editor/common/modes/modesFilters.ts +++ /dev/null @@ -1,50 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {isFalsyOrEmpty} from 'vs/base/common/arrays'; -import * as filters from 'vs/base/common/filters'; -import {ISuggestion, ISuggestionFilter} from 'vs/editor/common/modes'; - -export type IMatch = filters.IMatch; - -function wrapBaseFilter(filter: filters.IFilter): ISuggestionFilter { - return (word: string, suggestion: ISuggestion): filters.IMatch[] => { - - let result = filter(word, suggestion.label); - if (!isFalsyOrEmpty(result)) { - return result; - } - - // check for match but don't produce highlights - if (suggestion.codeSnippet !== suggestion.label) { - if (!isFalsyOrEmpty(filter(word, suggestion.codeSnippet.replace(/{{.+?}}/g, '')))) { // filters {{text}}-snippet syntax - return [{ start: 0, end: 0 }]; - } - } - if (typeof suggestion.filterText === 'string') { - if (!isFalsyOrEmpty(filter(word, suggestion.filterText))) { - return [{ start: 0, end: 0 }]; - } - } - }; -} - -export var StrictPrefix: ISuggestionFilter = wrapBaseFilter(filters.matchesStrictPrefix); -export var Prefix: ISuggestionFilter = wrapBaseFilter(filters.matchesPrefix); -export var CamelCase: ISuggestionFilter = wrapBaseFilter(filters.matchesCamelCase); -export var ContiguousSubString: ISuggestionFilter = wrapBaseFilter(filters.matchesContiguousSubString); - -// Combined Filters - -export function or(first: ISuggestionFilter, second: ISuggestionFilter): ISuggestionFilter { - return (word, suggestion) => first(word, suggestion) || second(word, suggestion); -} - -export function and(first: ISuggestionFilter, second: ISuggestionFilter): ISuggestionFilter { - return (word, suggestion) => first(word, suggestion) && second(word, suggestion); -} - -export var DefaultFilter = or(or(Prefix, CamelCase), ContiguousSubString); \ No newline at end of file diff --git a/src/vs/editor/common/modes/supports/suggestSupport.ts b/src/vs/editor/common/modes/supports/suggestSupport.ts index da43a161f3d..1cd7e845b6f 100644 --- a/src/vs/editor/common/modes/supports/suggestSupport.ts +++ b/src/vs/editor/common/modes/supports/suggestSupport.ts @@ -7,8 +7,8 @@ import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import {IModel, IPosition} from 'vs/editor/common/editorCommon'; -import {ILineContext, IMode, ISuggestResult, ISuggestSupport, ISuggestion, ISuggestionFilter} from 'vs/editor/common/modes'; -import {DefaultFilter, StrictPrefix} from 'vs/editor/common/modes/modesFilters'; +import {ILineContext, IMode, ISuggestResult, ISuggestSupport, ISuggestion} from 'vs/editor/common/modes'; +import {IFilter, matchesStrictPrefix, fuzzyContiguousFilter} from 'vs/base/common/filters'; import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports'; import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; import {IModelService} from 'vs/editor/common/services/modelService'; @@ -60,10 +60,6 @@ export class SuggestSupport implements ISuggestSupport { }); } - public getFilter(): ISuggestionFilter { - return DefaultFilter; - } - public getTriggerCharacters(): string[] { return this.contribution.triggerCharacters; } @@ -87,8 +83,8 @@ export class TextualSuggestSupport implements ISuggestSupport { return this._editorWorkerService.textualSuggest(resource, position); } - public getFilter(): ISuggestionFilter { - return StrictPrefix; + public get filter(): IFilter { + return matchesStrictPrefix; } public getTriggerCharacters(): string[] { @@ -171,12 +167,12 @@ export function filterSuggestions(value: ISuggestResult): ISuggestResult[] { return; } // filter suggestions - var accept = DefaultFilter, + var accept = fuzzyContiguousFilter, result: ISuggestResult[] = []; result.push({ currentWord: value.currentWord, - suggestions: value.suggestions.filter((element) => !!accept(value.currentWord, element)), + suggestions: value.suggestions.filter((element) => !!accept(value.currentWord, element.label)), incomplete: value.incomplete }); diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index e8d071e30cf..2b0e898c656 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -9,13 +9,13 @@ import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import {IRequestHandler} from 'vs/base/common/worker/simpleWorker'; import {Range} from 'vs/editor/common/core/range'; +import {fuzzyContiguousFilter} from 'vs/base/common/filters'; import {DiffComputer} from 'vs/editor/common/diff/diffComputer'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2'; import {WordHelper} from 'vs/editor/common/model/textModelWithTokensHelpers'; import {IInplaceReplaceSupportResult, ILink, ISuggestResult, ISuggestion} from 'vs/editor/common/modes'; import {computeLinks} from 'vs/editor/common/modes/linkComputer'; -import {DefaultFilter} from 'vs/editor/common/modes/modesFilters'; import {BasicInplaceReplace} from 'vs/editor/common/modes/supports/inplaceReplaceSupport'; import {EditorSimpleWorker, IRawModelData} from 'vs/editor/common/services/editorSimpleWorkerCommon'; @@ -214,12 +214,11 @@ export class EditorSimpleWorkerImpl extends EditorSimpleWorker implements IReque private _suggestFiltered(model:MirrorModel, position: editorCommon.IPosition, wordDefRegExp: RegExp): ISuggestResult[] { let value = this._suggestUnfiltered(model, position, wordDefRegExp); - let accept = DefaultFilter; // filter suggestions return [{ currentWord: value.currentWord, - suggestions: value.suggestions.filter((element) => !!accept(value.currentWord, element)), + suggestions: value.suggestions.filter((element) => !!fuzzyContiguousFilter(value.currentWord, element.label)), incomplete: value.incomplete }]; } diff --git a/src/vs/editor/contrib/suggest/browser/completionModel.ts b/src/vs/editor/contrib/suggest/browser/completionModel.ts index e2efb1678b2..8d832e6b91f 100644 --- a/src/vs/editor/contrib/suggest/browser/completionModel.ts +++ b/src/vs/editor/contrib/suggest/browser/completionModel.ts @@ -10,8 +10,8 @@ import {assign} from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import {IPosition} from 'vs/editor/common/editorCommon'; -import {ISuggestResult, ISuggestSupport, ISuggestion, ISuggestionFilter} from 'vs/editor/common/modes'; -import {DefaultFilter, IMatch} from 'vs/editor/common/modes/modesFilters'; +import {IFilter, IMatch, fuzzyContiguousFilter} from 'vs/base/common/filters'; +import {ISuggestResult, ISuggestSupport, ISuggestion} from 'vs/editor/common/modes'; import {ISuggestResult2} from '../common/suggest'; export class CompletionItem { @@ -19,15 +19,15 @@ export class CompletionItem { suggestion: ISuggestion; highlights: IMatch[]; container: ISuggestResult; + filter: IFilter; - private _filter: ISuggestionFilter; private _support: ISuggestSupport; constructor(suggestion: ISuggestion, container: ISuggestResult2) { this._support = container.support; this.suggestion = suggestion; this.container = container; - this._filter = container.support && container.support.getFilter() || DefaultFilter; + this.filter = container.support && container.support.filter || fuzzyContiguousFilter; } resolveDetails(resource: URI, position: IPosition): TPromise { @@ -42,10 +42,6 @@ export class CompletionItem { this.suggestion = assign(this.suggestion, value); } - updateHighlights(word: string): void { - this.highlights = this._filter(word, this.suggestion); - } - static compare(item: CompletionItem, otherItem: CompletionItem): number { const suggestion = item.suggestion; const otherSuggestion = otherItem.suggestion; @@ -115,12 +111,27 @@ export class CompletionModel { overwriteBefore = item.container.currentWord.length; } - let start = leadingLineContent.length - (overwriteBefore + characterCountDelta); - let word = leadingLineContent.substr(start); + const start = leadingLineContent.length - (overwriteBefore + characterCountDelta); + const word = leadingLineContent.substr(start); - // filter word - item.updateHighlights(word); - if (!isFalsyOrEmpty(item.highlights)) { + const {filter, suggestion} = item; + let match = false; + + // compute highlights based on 'label' + item.highlights = filter(word, suggestion.label); + match = !isFalsyOrEmpty(item.highlights); + + // no match on label -> check on codeSnippet + if (!match && suggestion.codeSnippet !== suggestion.label) { + match = !isFalsyOrEmpty((filter(word, suggestion.codeSnippet.replace(/{{.+?}}/g, '')))); // filters {{text}}-snippet syntax + } + + // no match on label nor codeSnippet -> check on filterText + if(!match && typeof suggestion.filterText === 'string') { + match = !isFalsyOrEmpty(filter(word, suggestion.filterText)); + } + + if (match) { this._filteredItems.push(item); } } diff --git a/src/vs/languages/typescript/common/languageFeatures.ts b/src/vs/languages/typescript/common/languageFeatures.ts index c1a2b976617..d877a51294e 100644 --- a/src/vs/languages/typescript/common/languageFeatures.ts +++ b/src/vs/languages/typescript/common/languageFeatures.ts @@ -240,10 +240,6 @@ class SuggestAdapter extends Adapter implements modes.ISuggestSupport { return 'variable'; } - getFilter(): modes.ISuggestionFilter { - return; - } - getTriggerCharacters(): string[] { return ['.']; } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 4aabdbc49df..dc0fb92ba5a 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -5,7 +5,6 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import {DefaultFilter} from 'vs/editor/common/modes/modesFilters'; import {TPromise} from 'vs/base/common/winjs.base'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {Remotable, IThreadService} from 'vs/platform/thread/common/thread'; @@ -579,9 +578,6 @@ class SuggestAdapter implements modes.ISuggestSupport { }); } - getFilter(): any { - throw new Error('illegal state'); - } getTriggerCharacters(): string[] { throw new Error('illegal state'); } @@ -1035,9 +1031,6 @@ export class MainThreadLanguageFeatures { getSuggestionDetails: (resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise => { return this._proxy.$getSuggestionDetails(handle, resource, position, suggestion); }, - getFilter() { - return DefaultFilter; - }, getTriggerCharacters(): string[] { return triggerCharacters; },