diff --git a/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts index 1bea497e55baebb04847539cb0b47d8409f6167c..34340d578e05044692c6313cde1b28741878afbd 100644 --- a/src/vs/editor/common/modes/languageSelector.ts +++ b/src/vs/editor/common/modes/languageSelector.ts @@ -20,62 +20,86 @@ export default function matches(selection: LanguageSelector, uri: URI, language: return score(selection, uri, language) > 0; } -export function score(selector: LanguageSelector, uri: URI, language: string): number { +export function score(selector: LanguageSelector, candidateUri: URI, candidateLanguage: string): number { if (Array.isArray(selector)) { - // for each - let values = (selector).map(item => score(item, uri, language)); - return Math.max(...values); + // array -> take max individual value + let ret = 0; + for (const filter of selector) { + const value = score(filter, candidateUri, candidateLanguage); + if (value === 10) { + return value; // already at the highest + } + if (value > ret) { + ret = value; + } + } + return ret; } else if (typeof selector === 'string') { - // compare language id - if (selector === language) { - return 10; - } else if (selector === '*') { + // short-hand notion, desugars to + // 'fooLang' -> [{ language: 'fooLang', scheme: 'file' }, { language: 'fooLang', scheme: 'untitled' }] + // '*' -> { language: '*', scheme: '*' } + if (selector === '*') { return 5; + } else if (selector === candidateLanguage && _defaultSchemes[candidateUri.scheme]) { + return 10; } else { return 0; } + } else if (selector) { - // all must match but only highest score counts - const filter = selector; - - let valueLanguage = 0; - let valueScheme = 0; - let valuePattern = 0; - - // language id - if (filter.language) { - if (filter.language === language) { - valueLanguage = 10; - } else if (filter.language === '*') { - valueLanguage = 5; + // filter -> select accordingly, use defaults for scheme + const { language, pattern, scheme } = selector; + + let ret = 0; + + if (scheme) { + if (scheme === candidateUri.scheme) { + ret = 10; + } else if (scheme === '*') { + ret = 5; } else { return 0; } } - // scheme - if (filter.scheme) { - if (filter.scheme === uri.scheme) { - valueScheme = 10; + if (language) { + if (language === candidateLanguage) { + ret = 10; + } else if (language === '*') { + ret = Math.max(ret, 5); } else { return 0; } } - // match fsPath with pattern - if (filter.pattern) { - if (filter.pattern === uri.fsPath) { - valuePattern = 10; - } else if (matchGlobPattern(filter.pattern, uri.fsPath)) { - valuePattern = 5; + if (pattern) { + if (pattern === candidateUri.fsPath || matchGlobPattern(pattern, candidateUri.fsPath)) { + ret = 10; } else { return 0; } } - return Math.max(valueLanguage, valueScheme, valuePattern); + if (!_defaultSchemes[candidateUri.scheme] && !scheme && language !== '*') { + // undo match when the uri-scheme is special and not + // explicitly selected + return 0; + } else { + return ret; + } + + } else { + return undefined; } - return undefined; } + +interface DefaultSchemes { + file: 'file'; + untitled: 'untitled'; +} + +const _defaultSchemes: DefaultSchemes = Object.create(null); +_defaultSchemes.file = 'file'; +_defaultSchemes.untitled = 'untitled'; diff --git a/src/vs/editor/contrib/quickFix/test/common/quickFixModel.test.ts b/src/vs/editor/contrib/quickFix/test/common/quickFixModel.test.ts index 18d8e0e39281991c7ebb25c92861125b4f457dbe..721ab0348b736fc8b6597820f0444c350a67141d 100644 --- a/src/vs/editor/contrib/quickFix/test/common/quickFixModel.test.ts +++ b/src/vs/editor/contrib/quickFix/test/common/quickFixModel.test.ts @@ -18,7 +18,7 @@ import { CodeActionProviderRegistry, LanguageIdentifier } from 'vs/editor/common suite('QuickFix', () => { const languageIdentifier = new LanguageIdentifier('foo-lang', 3); - let uri = URI.parse('fake:path'); + let uri = URI.parse('untitled:path'); let model = Model.createFromString('foobar foo bar\nfarboo far boo', undefined, languageIdentifier, uri); let markerService: MarkerService; let editor: ICommonCodeEditor; diff --git a/src/vs/editor/contrib/suggest/test/common/suggest.test.ts b/src/vs/editor/contrib/suggest/test/common/suggest.test.ts index e4611538bd4504f60a7d26162c1ee16663715b92..f6f26c34ddf0ff2caa166ab82cb2f25909567be6 100644 --- a/src/vs/editor/contrib/suggest/test/common/suggest.test.ts +++ b/src/vs/editor/contrib/suggest/test/common/suggest.test.ts @@ -21,7 +21,7 @@ suite('Suggest', function () { setup(function () { model = Model.createFromString('FOO\nbar\BAR\nfoo', undefined, undefined, URI.parse('foo:bar/path')); - registration = SuggestRegistry.register({ pattern: 'bar/path' }, { + registration = SuggestRegistry.register({ pattern: 'bar/path', scheme: 'foo' }, { provideCompletionItems() { return { incomplete: false, @@ -98,7 +98,7 @@ suite('Suggest', function () { }; } }; - const registration = SuggestRegistry.register({ pattern: 'bar/path' }, foo); + const registration = SuggestRegistry.register({ pattern: 'bar/path', scheme: 'foo' }, foo); provideSuggestionItems(model, new Position(1, 1), undefined, [foo]).then(items => { registration.dispose(); diff --git a/src/vs/editor/test/common/modes/languageSelector.test.ts b/src/vs/editor/test/common/modes/languageSelector.test.ts index 19845bef2d6d3bd137b0d2b3479898987d55556e..18d183b0cb320ee990695b74e62dc0dd529a033e 100644 --- a/src/vs/editor/test/common/modes/languageSelector.test.ts +++ b/src/vs/editor/test/common/modes/languageSelector.test.ts @@ -26,6 +26,26 @@ suite('LanguageSelector', function () { test('score, any language', function () { assert.equal(score({ language: '*' }, model.uri, model.language), 5); assert.equal(score('*', model.uri, model.language), 5); + + assert.equal(score('*', URI.parse('foo:bar'), model.language), 5); + assert.equal(score('farboo', URI.parse('foo:bar'), model.language), 0); + }); + + test('score, default schemes', function () { + + const uri = URI.parse('git:foo/file.txt'); + const language = 'farboo'; + + assert.equal(score('*', uri, language), 5); + assert.equal(score('farboo', uri, language), 0); + assert.equal(score({ language: 'farboo', scheme: '' }, uri, language), 0); + assert.equal(score({ language: 'farboo', scheme: 'git' }, uri, language), 10); + assert.equal(score({ language: 'farboo', scheme: '*' }, uri, language), 10); + assert.equal(score({ language: 'farboo' }, uri, language), 0); + assert.equal(score({ language: '*' }, uri, language), 5); + + assert.equal(score({ scheme: '*' }, uri, language), 5); + assert.equal(score({ scheme: 'git' }, uri, language), 10); }); test('score, filter', function () { @@ -34,8 +54,10 @@ suite('LanguageSelector', function () { assert.equal(score({ language: 'farboo', scheme: 'file' }, model.uri, model.language), 10); assert.equal(score({ language: 'farboo', scheme: 'http' }, model.uri, model.language), 0); - assert.equal(score({ pattern: '**/*.fb' }, model.uri, model.language), 5); - // assert.equal(score({ pattern: '/testbed/file.fb' }, model.uri, model.language), 10); fails on windows + assert.equal(score({ pattern: '**/*.fb' }, model.uri, model.language), 10); + assert.equal(score({ pattern: '**/*.fb', scheme: 'file' }, model.uri, model.language), 10); + assert.equal(score({ pattern: '**/*.fb' }, URI.parse('foo:bar'), model.language), 0); + assert.equal(score({ pattern: '**/*.fb', scheme: 'foo' }, URI.parse('foo:bar'), model.language), 0); }); test('score, max(filters)', function () { @@ -45,7 +67,8 @@ suite('LanguageSelector', function () { assert.equal(score(match, model.uri, model.language), 10); assert.equal(score(fail, model.uri, model.language), 0); assert.equal(score([match, fail], model.uri, model.language), 10); + assert.equal(score([fail, fail], model.uri, model.language), 0); assert.equal(score(['farboo', '*'], model.uri, model.language), 10); assert.equal(score(['*', 'farboo'], model.uri, model.language), 10); }); -}); \ No newline at end of file +});