Path: blob/main/src/vs/editor/common/languageSelector.ts
3292 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IRelativePattern, match as matchGlobPattern } from '../../base/common/glob.js';6import { URI } from '../../base/common/uri.js';7import { normalize } from '../../base/common/path.js';89export interface LanguageFilter {10readonly language?: string;11readonly scheme?: string;12readonly pattern?: string | IRelativePattern;13readonly notebookType?: string;14/**15* This provider is implemented in the UI thread.16*/17readonly hasAccessToAllModels?: boolean;18readonly exclusive?: boolean;1920/**21* This provider comes from a builtin extension.22*/23readonly isBuiltin?: boolean;24}2526export type LanguageSelector = string | LanguageFilter | ReadonlyArray<string | LanguageFilter>;2728export function score(selector: LanguageSelector | undefined, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean, candidateNotebookUri: URI | undefined, candidateNotebookType: string | undefined): number {2930if (Array.isArray(selector)) {31// array -> take max individual value32let ret = 0;33for (const filter of selector) {34const value = score(filter, candidateUri, candidateLanguage, candidateIsSynchronized, candidateNotebookUri, candidateNotebookType);35if (value === 10) {36return value; // already at the highest37}38if (value > ret) {39ret = value;40}41}42return ret;4344} else if (typeof selector === 'string') {4546if (!candidateIsSynchronized) {47return 0;48}4950// short-hand notion, desugars to51// 'fooLang' -> { language: 'fooLang'}52// '*' -> { language: '*' }53if (selector === '*') {54return 5;55} else if (selector === candidateLanguage) {56return 10;57} else {58return 0;59}6061} else if (selector) {62// filter -> select accordingly, use defaults for scheme63const { language, pattern, scheme, hasAccessToAllModels, notebookType } = selector as LanguageFilter; // TODO: microsoft/TypeScript#427686465if (!candidateIsSynchronized && !hasAccessToAllModels) {66return 0;67}6869// selector targets a notebook -> use the notebook uri instead70// of the "normal" document uri.71if (notebookType && candidateNotebookUri) {72candidateUri = candidateNotebookUri;73}7475let ret = 0;7677if (scheme) {78if (scheme === candidateUri.scheme) {79ret = 10;80} else if (scheme === '*') {81ret = 5;82} else {83return 0;84}85}8687if (language) {88if (language === candidateLanguage) {89ret = 10;90} else if (language === '*') {91ret = Math.max(ret, 5);92} else {93return 0;94}95}9697if (notebookType) {98if (notebookType === candidateNotebookType) {99ret = 10;100} else if (notebookType === '*' && candidateNotebookType !== undefined) {101ret = Math.max(ret, 5);102} else {103return 0;104}105}106107if (pattern) {108let normalizedPattern: string | IRelativePattern;109if (typeof pattern === 'string') {110normalizedPattern = pattern;111} else {112// Since this pattern has a `base` property, we need113// to normalize this path first before passing it on114// because we will compare it against `Uri.fsPath`115// which uses platform specific separators.116// Refs: https://github.com/microsoft/vscode/issues/99938117normalizedPattern = { ...pattern, base: normalize(pattern.base) };118}119120if (normalizedPattern === candidateUri.fsPath || matchGlobPattern(normalizedPattern, candidateUri.fsPath)) {121ret = 10;122} else {123return 0;124}125}126127return ret;128129} else {130return 0;131}132}133134135export function targetsNotebooks(selector: LanguageSelector): boolean {136if (typeof selector === 'string') {137return false;138} else if (Array.isArray(selector)) {139return selector.some(targetsNotebooks);140} else {141return !!(<LanguageFilter>selector).notebookType;142}143}144145146