Remove unused test files and tokenization modules

- Deleted `windowDelineation.test.ts` as it is no longer needed.
- Removed `index.ts` and `tokenizer.ts` from the tokenization module due to refactoring.
- Eliminated unused types related to authentication, code citation, context provider API, and core functionalities.
- Cleaned up the `status.ts` file by removing the `StatusKind` type definition.
This commit is contained in:
2026-02-16 22:49:32 +08:00
parent 71a71530a3
commit 0d25f4d1ef
346 changed files with 17 additions and 120182 deletions
+6 -4
View File
@@ -1,9 +1,11 @@
# rules.md
在构建这个LLM应用网页时,你需要基于VUE3开发。我需要前端只运行渲染和数据回传,后端负责llm api调用,inline suggustions实现和数据解析。
在构建这个LLM应用网页时,你需要基于VUE3开发。我需要前端只运行渲染和数据回传,后端负责llm api调用,类似copilet的auto inline suggustions实现和数据解析。
## 指导原则
- 不要擅自用npm或者yarn运行网页,你既看不到网页的内容,也无法阻止命令暂停
- 应该保证代码效率,不多定义变量,不写冗余注释,把降低延迟放在第一位
- 每次完成任务前都要反复检查代码,确保代码准确无误
- 不要擅自用npm或者yarn运行网页,你既看不到网页的内容,也无法阻止命令暂停。但是,你可以用npm run build检查代码。
- 应该保证代码效率,不多定义变量,不写冗余注释,把降低延迟放在第一位
- 每次完成任务前都要反复阅读检查代码,确保代码准确无误
- 尽量不要搜索关键字,而是了解代码结构后查询整个问题代码明确问题所在。
- @/milkdown-docs/ 代表milkdown的最新官方文档,不要修改,涉及到前端编辑器的指令时要核对官方文档。
+11 -1
View File
@@ -1,4 +1,11 @@
from typing import Tuple
from datetime import datetime, timezone, timedelta
def _get_current_datetime() -> str:
now = datetime.now(timezone(timedelta(hours=8)))
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
weekday = weekdays[now.weekday()]
return f"{now.year}{now.month}{now.day}{weekday} {now.hour:02d}:{now.minute:02d}:{now.second:02d}"
def _sanitize_language_id(language_id: str) -> str:
if not language_id:
@@ -25,8 +32,11 @@ def prepare_prompt_context(prefix: str, suffix: str) -> Tuple[str, str]:
def build_prompt(prefix: str, suffix: str, language_id: str = "markdown") -> str:
safe_language_id = _sanitize_language_id(language_id)
recent_prefix, recent_suffix = _prepare_context(prefix, suffix)
current_time = _get_current_datetime()
prompt = f"""You are an inline completion engine for a {safe_language_id} editor with ghost-text suggestions.
prompt = f"""Current time: {current_time}
You are an inline completion engine for a {safe_language_id} editor with ghost-text suggestions.
Your job:
- Return ONLY the text that should be inserted at the cursor between PREFIX and SUFFIX.
@@ -1,76 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITelemetryService, TelemetryEventMeasurements, TelemetryEventProperties } from '../../../../../platform/telemetry/common/telemetry';
import { wrapEventNameForPrefixRemoval } from '../../../../../platform/telemetry/node/azureInsightsReporter';
import { createServiceIdentifier } from '../../../../../util/common/services';
import { TelemetryMeasurements, TelemetryProperties, TelemetryStore } from '../../lib/src/telemetry';
import type { TelemetrySpy } from '../../lib/src/test/telemetrySpy';
export const ICompletionsTelemetryService = createServiceIdentifier<ICompletionsTelemetryService>('completionsTelemetryService');
export interface ICompletionsTelemetryService {
readonly _serviceBrand: undefined;
sendGHTelemetryEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void;
sendEnhancedGHTelemetryEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void;
sendGHTelemetryErrorEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void;
sendGHTelemetryException(maybeError: unknown, origin: string, store?: TelemetryStore): void;
setSpyReporters(reporter: TelemetrySpy, enhancedReporter: TelemetrySpy): void;
clearSpyReporters(): void;
}
export class CompletionsTelemetryServiceBridge implements ICompletionsTelemetryService {
declare _serviceBrand: undefined;
private reporter: TelemetrySpy | undefined;
private enhancedReporter: TelemetrySpy | undefined;
constructor(
@ITelemetryService private readonly telemetryService: ITelemetryService
) {
this.reporter = undefined;
this.enhancedReporter = undefined;
}
sendGHTelemetryEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void {
this.telemetryService.sendGHTelemetryEvent(wrapEventNameForPrefixRemoval(`copilot/${eventName}`), properties, measurements);
this.getSpyReporters(store ?? TelemetryStore.Standard)?.sendTelemetryEvent(eventName, properties as TelemetryProperties, measurements as TelemetryMeasurements);
}
sendEnhancedGHTelemetryEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void {
this.telemetryService.sendEnhancedGHTelemetryEvent(wrapEventNameForPrefixRemoval(`copilot/${eventName}`), properties, measurements);
this.getSpyReporters(store ?? TelemetryStore.Enhanced)?.sendTelemetryEvent(eventName, properties as TelemetryProperties, measurements as TelemetryMeasurements);
}
sendGHTelemetryErrorEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, store?: TelemetryStore): void {
this.telemetryService.sendGHTelemetryErrorEvent(wrapEventNameForPrefixRemoval(`copilot/${eventName}`), properties, measurements);
this.getSpyReporters(store ?? TelemetryStore.Enhanced)?.sendTelemetryErrorEvent(eventName, properties as TelemetryProperties, measurements as TelemetryMeasurements);
}
sendGHTelemetryException(maybeError: unknown, origin: string, store?: TelemetryStore): void {
this.telemetryService.sendGHTelemetryException(maybeError, origin);
if (maybeError instanceof Error) {
this.getSpyReporters(store ?? TelemetryStore.Enhanced)?.sendTelemetryException(maybeError as Error, undefined, undefined);
}
}
setSpyReporters(reporter: TelemetrySpy, enhancedReporter: TelemetrySpy) {
this.reporter = reporter;
this.enhancedReporter = enhancedReporter;
}
clearSpyReporters() {
this.reporter = undefined;
this.enhancedReporter = undefined;
}
private getSpyReporters(store: TelemetryStore): TelemetrySpy | undefined {
if (TelemetryStore.isEnhanced(store)) {
return this.enhancedReporter;
} else {
return this.reporter;
}
}
}
@@ -1,262 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { commands, env } from 'vscode';
import { ILogService } from '../../../platform/log/common/logService';
import { outputChannel } from '../../../platform/log/vscode/outputChannelLogTarget';
import { DisposableStore, IDisposable } from '../../../util/vs/base/common/lifecycle';
import { URI } from '../../../util/vs/base/common/uri';
import { SyncDescriptor } from '../../../util/vs/platform/instantiation/common/descriptors';
import { IInstantiationService, ServicesAccessor } from '../../../util/vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from '../../../util/vs/platform/instantiation/common/serviceCollection';
import { CompletionsTelemetryServiceBridge, ICompletionsTelemetryService } from './bridge/src/completionsTelemetryServiceBridge';
import { LoggingCitationManager } from './extension/src/codeReferencing/citationManager';
import { CompletionsObservableWorkspace } from './extension/src/completionsObservableWorkspace';
import { disableCompletions, enableCompletions, toggleCompletions, VSCodeConfigProvider, VSCodeEditorInfo } from './extension/src/config';
import { CMDDisableCompletionsChat, CMDDisableCompletionsClient, CMDEnableCompletionsChat, CMDEnableCompletionsClient, CMDOpenDocumentationClient, CMDOpenLogsClient, CMDOpenModelPickerChat, CMDOpenModelPickerClient, CMDToggleCompletionsChat, CMDToggleCompletionsClient, CMDToggleStatusMenuChat, CMDToggleStatusMenuClient } from './extension/src/constants';
import { contextProviderMatch } from './extension/src/contextProviderMatch';
import { registerPanelSupport } from './extension/src/copilotPanel/common';
import { CopilotExtensionStatus, ICompletionsExtensionStatus } from './extension/src/extensionStatus';
import { extensionFileSystem } from './extension/src/fileSystem';
import { ModelPickerManager } from './extension/src/modelPicker';
import { CopilotStatusBar } from './extension/src/statusBar';
import { CopilotStatusBarPickMenu } from './extension/src/statusBarPicker';
import { ExtensionTextDocumentManager } from './extension/src/textDocumentManager';
import { exception } from './extension/src/vscodeInlineCompletionItemProvider';
import { CopilotTokenManagerImpl, ICompletionsCopilotTokenManager } from './lib/src/auth/copilotTokenManager';
import { ICompletionsCitationManager } from './lib/src/citationManager';
import { CompletionNotifier, ICompletionsNotifierService } from './lib/src/completionNotifier';
import { ICompletionsObservableWorkspace } from './lib/src/completionsObservableWorkspace';
import { ICompletionsConfigProvider, ICompletionsEditorAndPluginInfo } from './lib/src/config';
import { registerDocumentTracker } from './lib/src/documentTracker';
import { ICompletionsUserErrorNotifierService, UserErrorNotifier } from './lib/src/error/userErrorNotifier';
import { setupCompletionsExperimentationService } from './lib/src/experiments/defaultExpFilters';
import { Features } from './lib/src/experiments/features';
import { ICompletionsFeaturesService } from './lib/src/experiments/featuresService';
import { FileReader, ICompletionsFileReaderService } from './lib/src/fileReader';
import { ICompletionsFileSystemService } from './lib/src/fileSystem';
import { AsyncCompletionManager, ICompletionsAsyncManagerService } from './lib/src/ghostText/asyncCompletions';
import { CompletionsCache, ICompletionsCacheService } from './lib/src/ghostText/completionsCache';
import { ConfigBlockModeConfig, ICompletionsBlockModeConfig } from './lib/src/ghostText/configBlockMode';
import { CurrentGhostText, ICompletionsCurrentGhostText } from './lib/src/ghostText/current';
import { ICompletionsLastGhostText, LastGhostText } from './lib/src/ghostText/last';
import { ICompletionsSpeculativeRequestCache, SpeculativeRequestCache } from './lib/src/ghostText/speculativeRequestCache';
import { ICompletionsLogTargetService, LogLevel } from './lib/src/logger';
import { formatLogMessage } from './lib/src/logging/util';
import { CompletionsFetcher, ICompletionsFetcherService } from './lib/src/networking';
import { ExtensionNotificationSender, ICompletionsNotificationSender } from './lib/src/notificationSender';
import { ICompletionsOpenAIFetcherService, LiveOpenAIFetcher } from './lib/src/openai/fetch';
import { AvailableModelsManager, ICompletionsModelManagerService } from './lib/src/openai/model';
import { ICompletionsStatusReporter } from './lib/src/progress';
import {
CompletionsPromptFactory, ICompletionsPromptFactoryService
} from './lib/src/prompt/completionsPromptFactory/completionsPromptFactory';
import { ContextProviderBridge, ICompletionsContextProviderBridgeService } from './lib/src/prompt/components/contextProviderBridge';
import {
CachedContextProviderRegistry,
CoreContextProviderRegistry,
DefaultContextProvidersContainer, ICompletionsContextProviderRegistryService,
ICompletionsDefaultContextProviders
} from './lib/src/prompt/contextProviderRegistry';
import { ContextProviderStatistics, ICompletionsContextProviderService } from './lib/src/prompt/contextProviderStatistics';
import { FullRecentEditsProvider, ICompletionsRecentEditsProviderService } from './lib/src/prompt/recentEdits/recentEditsProvider';
import { CompositeRelatedFilesProvider } from './lib/src/prompt/similarFiles/compositeRelatedFilesProvider';
import { ICompletionsRelatedFilesProviderService } from './lib/src/prompt/similarFiles/relatedFiles';
import { ICompletionsTelemetryUserConfigService, TelemetryUserConfig } from './lib/src/telemetry/userConfig';
import { ICompletionsTextDocumentManagerService } from './lib/src/textDocumentManager';
import { ICompletionsPromiseQueueService, PromiseQueue } from './lib/src/util/promiseQueue';
import { ICompletionsRuntimeModeService, RuntimeMode } from './lib/src/util/runtimeMode';
/** @public */
export function createContext(serviceAccessor: ServicesAccessor, store: DisposableStore): IInstantiationService {
const logService = serviceAccessor.get(ILogService);
const serviceCollection = new ServiceCollection();
serviceCollection.set(ICompletionsLogTargetService, new class implements ICompletionsLogTargetService {
declare _serviceBrand: undefined;
logIt(level: LogLevel, category: string, ...extra: unknown[]): void {
const msg = formatLogMessage(category, ...extra);
switch (level) {
case LogLevel.DEBUG: return logService.debug(msg);
case LogLevel.INFO: return logService.info(msg);
case LogLevel.WARN: return logService.warn(msg);
case LogLevel.ERROR: return logService.error(msg);
}
}
});
serviceCollection.set(ICompletionsRuntimeModeService, RuntimeMode.fromEnvironment(false));
serviceCollection.set(ICompletionsCacheService, new CompletionsCache());
serviceCollection.set(ICompletionsConfigProvider, new VSCodeConfigProvider());
serviceCollection.set(ICompletionsLastGhostText, new LastGhostText());
serviceCollection.set(ICompletionsCurrentGhostText, new CurrentGhostText());
serviceCollection.set(ICompletionsSpeculativeRequestCache, new SpeculativeRequestCache());
serviceCollection.set(ICompletionsNotificationSender, new SyncDescriptor(ExtensionNotificationSender));
serviceCollection.set(ICompletionsEditorAndPluginInfo, new VSCodeEditorInfo());
serviceCollection.set(ICompletionsExtensionStatus, new CopilotExtensionStatus());
serviceCollection.set(ICompletionsFeaturesService, new SyncDescriptor(Features));
serviceCollection.set(ICompletionsObservableWorkspace, new SyncDescriptor(CompletionsObservableWorkspace));
serviceCollection.set(ICompletionsStatusReporter, new SyncDescriptor(CopilotStatusBar, ['github.copilot.languageStatus']));
serviceCollection.set(ICompletionsCopilotTokenManager, new SyncDescriptor(CopilotTokenManagerImpl, [false]));
serviceCollection.set(ICompletionsTextDocumentManagerService, new SyncDescriptor(ExtensionTextDocumentManager));
serviceCollection.set(ICompletionsFileReaderService, new SyncDescriptor(FileReader));
serviceCollection.set(ICompletionsBlockModeConfig, new SyncDescriptor(ConfigBlockModeConfig));
serviceCollection.set(ICompletionsTelemetryService, new SyncDescriptor(CompletionsTelemetryServiceBridge));
serviceCollection.set(ICompletionsTelemetryUserConfigService, new SyncDescriptor(TelemetryUserConfig));
serviceCollection.set(ICompletionsRecentEditsProviderService, new SyncDescriptor(FullRecentEditsProvider, [undefined]));
serviceCollection.set(ICompletionsNotifierService, new SyncDescriptor(CompletionNotifier));
serviceCollection.set(ICompletionsOpenAIFetcherService, new SyncDescriptor(LiveOpenAIFetcher));
serviceCollection.set(ICompletionsModelManagerService, new SyncDescriptor(AvailableModelsManager, [true]));
serviceCollection.set(ICompletionsAsyncManagerService, new SyncDescriptor(AsyncCompletionManager));
serviceCollection.set(ICompletionsContextProviderBridgeService, new SyncDescriptor(ContextProviderBridge));
serviceCollection.set(ICompletionsUserErrorNotifierService, new SyncDescriptor(UserErrorNotifier));
serviceCollection.set(ICompletionsRelatedFilesProviderService, new SyncDescriptor(CompositeRelatedFilesProvider));
serviceCollection.set(ICompletionsFileSystemService, extensionFileSystem);
serviceCollection.set(ICompletionsContextProviderRegistryService, new SyncDescriptor(CachedContextProviderRegistry, [CoreContextProviderRegistry, contextProviderMatch]));
serviceCollection.set(ICompletionsPromiseQueueService, new PromiseQueue());
serviceCollection.set(ICompletionsCitationManager, new SyncDescriptor(LoggingCitationManager));
serviceCollection.set(ICompletionsContextProviderService, new ContextProviderStatistics());
serviceCollection.set(ICompletionsPromptFactoryService, new SyncDescriptor(CompletionsPromptFactory));
serviceCollection.set(ICompletionsFetcherService, new SyncDescriptor(CompletionsFetcher));
serviceCollection.set(ICompletionsDefaultContextProviders, new DefaultContextProvidersContainer());
return serviceAccessor.get(IInstantiationService).createChild(serviceCollection, store);
}
/** @public */
export function setup(serviceAccessor: ServicesAccessor, disposables: DisposableStore) {
// This must be registered before activation!
// CodeQuote needs to listen for the initial token notification event.
disposables.add(serviceAccessor.get(ICompletionsCitationManager).register());
// Register to listen for changes to the active document to keep track
// of last access time
disposables.add(registerDocumentTracker(serviceAccessor));
// Register the context providers enabled by default.
const defaultContextProviders = serviceAccessor.get(ICompletionsDefaultContextProviders);
defaultContextProviders.add('ms-vscode.cpptools');
defaultContextProviders.add('promptfile-ai-context-provider');
disposables.add(setupCompletionsExperimentationService(serviceAccessor));
}
export function registerUnificationCommands(accessor: ServicesAccessor): IDisposable {
const disposables = new DisposableStore();
disposables.add(registerEnablementCommands(accessor));
disposables.add(registerStatusBar(accessor));
disposables.add(registerDiagnosticCommands(accessor));
disposables.add(registerPanelSupport(accessor));
disposables.add(registerModelPickerCommands(accessor));
return disposables;
}
function registerEnablementCommands(accessor: ServicesAccessor): IDisposable {
const disposables = new DisposableStore();
const instantiationService = accessor.get(IInstantiationService);
// Enable/Disable/Toggle completions commands [with Command Palette support]
function enable(id: string): IDisposable {
return registerCommandWrapper(accessor, id, async () => {
await instantiationService.invokeFunction(enableCompletions);
});
}
function disable(id: string): IDisposable {
return registerCommandWrapper(accessor, id, async () => {
await instantiationService.invokeFunction(disableCompletions);
});
}
function toggle(id: string): IDisposable {
return registerCommandWrapper(accessor, id, async () => {
await instantiationService.invokeFunction(toggleCompletions);
});
}
// To support command palette
disposables.add(enable(CMDEnableCompletionsChat));
disposables.add(disable(CMDDisableCompletionsChat));
disposables.add(toggle(CMDToggleCompletionsChat));
// To support keybindings/main functionality
disposables.add(enable(CMDEnableCompletionsClient));
disposables.add(disable(CMDDisableCompletionsClient));
disposables.add(toggle(CMDToggleCompletionsClient));
return disposables;
}
function registerModelPickerCommands(accessor: ServicesAccessor): IDisposable {
const disposables = new DisposableStore();
const instantiationService = accessor.get(IInstantiationService);
const modelsPicker = instantiationService.createInstance(ModelPickerManager);
function registerModelPicker(commandId: string): IDisposable {
return registerCommandWrapper(accessor, commandId, async () => {
await modelsPicker.showModelPicker();
});
}
// Model picker command [with Command Palette support]
disposables.add(registerModelPicker(CMDOpenModelPickerClient));
disposables.add(registerModelPicker(CMDOpenModelPickerChat));
return disposables;
}
function registerStatusBar(accessor: ServicesAccessor): IDisposable {
const disposables = new DisposableStore();
const instantiationService = accessor.get(IInstantiationService);
const copilotTokenManagerService = accessor.get(ICompletionsCopilotTokenManager);
const extensionStatusService = accessor.get(ICompletionsExtensionStatus);
// Status menu command [with Command Palette support]
function registerStatusMenu(menuId: string): IDisposable {
return registerCommandWrapper(accessor, menuId, async () => {
if (extensionStatusService.kind === 'Error') {
// Try for a fresh token to clear up the error, but don't block the UI for too long.
await Promise.race([
copilotTokenManagerService.primeToken(),
new Promise(resolve => setTimeout(resolve, 100)),
]);
}
instantiationService.createInstance(CopilotStatusBarPickMenu).showStatusMenu();
});
}
disposables.add(registerStatusMenu(CMDToggleStatusMenuClient));
disposables.add(registerStatusMenu(CMDToggleStatusMenuChat));
return disposables;
}
function registerDiagnosticCommands(accessor: ServicesAccessor): IDisposable {
const disposables = new DisposableStore();
disposables.add(registerCommandWrapper(accessor, CMDOpenDocumentationClient, () => {
return env.openExternal(
URI.parse('https://docs.github.com/en/copilot/getting-started-with-github-copilot?tool=vscode')
);
}));
disposables.add(registerCommandWrapper(accessor, CMDOpenLogsClient, () => {
outputChannel.show();
}));
return disposables;
}
export function registerCommandWrapper(accessor: ServicesAccessor, command: string, fn: (...args: unknown[]) => unknown): IDisposable {
const instantiationService = accessor.get(IInstantiationService);
return commands.registerCommand(command, async (...args: unknown[]) => {
try {
await fn(...args);
} catch (error) {
instantiationService.invokeFunction(exception, error, command);
}
});
}
@@ -1,71 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { commands } from 'vscode';
import { CodeReference } from '.';
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { Disposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { onCopilotToken } from '../../../lib/src/auth/copilotTokenNotifier';
import { ICompletionsCitationManager, IPDocumentCitation } from '../../../lib/src/citationManager';
import { OutputPaneShowCommand } from '../../../lib/src/snippy/constants';
import { copilotOutputLogTelemetry } from '../../../lib/src/snippy/telemetryHandlers';
import { notify } from './matchNotifier';
import { GitHubCopilotLogger } from './outputChannel';
/**
* Citation manager that logs citations to the VS Code log. On the first citation encountered,
* the user gets a notification.
*/
export class LoggingCitationManager extends Disposable implements ICompletionsCitationManager {
declare _serviceBrand: undefined;
private logger?: GitHubCopilotLogger;
private readonly codeReference: CodeReference;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IAuthenticationService authenticationService: IAuthenticationService,
) {
super();
this.codeReference = this._register(this.instantiationService.createInstance(CodeReference));
const disposable = onCopilotToken(authenticationService, _ => {
if (this.logger) {
return;
}
this.logger = instantiationService.createInstance(GitHubCopilotLogger);
const initialNotificationCommand = commands.registerCommand(OutputPaneShowCommand, () =>
this.logger?.forceShow()
);
this.codeReference.addDisposable(initialNotificationCommand);
});
this.codeReference.addDisposable(disposable);
}
register() {
return this.codeReference.register();
}
async handleIPCodeCitation(citation: IPDocumentCitation): Promise<void> {
if (!this.codeReference.enabled || !this.logger || citation.details.length === 0) {
return;
}
const start = citation.location?.start;
const matchLocation = start ? `[Ln ${start.line + 1}, Col ${start.character + 1}]` : 'Location not available';
const shortenedMatchText = `${citation.matchingText
?.slice(0, 100)
.replace(/[\r\n\t]+|^[ \t]+/gm, ' ')
.trim()}...`;
this.logger.info(citation.inDocumentUri, `Similar code at `, matchLocation, shortenedMatchText);
for (const detail of citation.details) {
const { license, url } = detail;
this.logger.info(`License: ${license.replace('NOASSERTION', 'unknown')}, URL: ${url}`);
}
copilotOutputLogTelemetry.handleWrite({ instantiationService: this.instantiationService });
await this.instantiationService.invokeFunction(notify);
}
}
@@ -1,49 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TextEditor, window } from 'vscode';
import { Disposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { copilotOutputLogTelemetry } from '../../../lib/src/snippy/telemetryHandlers';
import { citationsChannelName } from './outputChannel';
export class CodeRefEngagementTracker extends Disposable {
private activeLog = false;
constructor(@IInstantiationService private instantiationService: IInstantiationService) {
super();
this._register(window.onDidChangeActiveTextEditor((e) => this.onActiveEditorChange(e)));
this._register(window.onDidChangeVisibleTextEditors((e) => this.onVisibleEditorsChange(e)));
}
onActiveEditorChange = (editor: TextEditor | undefined) => {
if (this.isOutputLog(editor)) {
copilotOutputLogTelemetry.handleFocus({ instantiationService: this.instantiationService });
}
};
onVisibleEditorsChange = (currEditors: readonly TextEditor[]) => {
const copilotLog = currEditors.find(e => this.isOutputLog(e));
if (this.activeLog) {
if (!copilotLog) {
this.activeLog = false;
}
} else if (copilotLog) {
this.activeLog = true;
copilotOutputLogTelemetry.handleOpen({ instantiationService: this.instantiationService });
}
};
get logVisible() {
return this.activeLog;
}
private isOutputLog = (editor: TextEditor | undefined) => {
return (
editor && editor.document.uri.scheme === 'output' && editor.document.uri.path.includes(citationsChannelName)
);
};
}
@@ -1,61 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vscode';
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { IDisposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { CopilotToken } from '../../../lib/src/auth/copilotTokenManager';
import { onCopilotToken } from '../../../lib/src/auth/copilotTokenNotifier';
import { ICompletionsLogTargetService } from '../../../lib/src/logger';
import { codeReferenceLogger } from '../../../lib/src/snippy/logger';
import { ICompletionsRuntimeModeService } from '../../../lib/src/util/runtimeMode';
import { CodeRefEngagementTracker } from './codeReferenceEngagementTracker';
export class CodeReference implements IDisposable {
subscriptions: Disposable | undefined;
event?: Disposable;
enabled: boolean = false;
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ICompletionsRuntimeModeService readonly _runtimeMode: ICompletionsRuntimeModeService,
@ICompletionsLogTargetService private readonly _logTarget: ICompletionsLogTargetService,
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
) { }
dispose() {
this.subscriptions?.dispose();
this.event?.dispose();
}
register() {
if (!this._runtimeMode.isRunningInTest()) {
this.event = onCopilotToken(this._authenticationService, (t) => this.onCopilotToken(t));
}
return this;
}
addDisposable(disposable: Disposable) {
if (!this.subscriptions) {
this.subscriptions = Disposable.from(disposable);
} else {
this.subscriptions = Disposable.from(this.subscriptions, disposable);
}
}
onCopilotToken = (token: Omit<CopilotToken, 'token'>) => {
this.enabled = token.codeQuoteEnabled || false;
if (!token.codeQuoteEnabled) {
this.subscriptions?.dispose();
this.subscriptions = undefined;
codeReferenceLogger.debug(this._logTarget, 'Public code references are disabled.');
return;
}
codeReferenceLogger.info(this._logTarget, 'Public code references are enabled.');
this.addDisposable(this._instantiationService.createInstance(CodeRefEngagementTracker));
};
}
@@ -1,58 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { commands, env, Uri } from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../platform/extContext/common/extensionContext';
import { IInstantiationService, ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { ICompletionsNotificationSender } from '../../../lib/src/notificationSender';
import { OutputPaneShowCommand } from '../../../lib/src/snippy/constants';
import { matchNotificationTelemetry, TelemetryActor } from '../../../lib/src/snippy/telemetryHandlers';
const matchCodeMessage =
'We found a reference to public code in a recent suggestion. To learn more about public code references, review the [documentation](https://aka.ms/github-copilot-match-public-code).';
const MatchAction = 'View reference';
const SettingAction = 'Change setting';
const CodeReferenceKey = 'codeReference.notified';
/**
* Displays a toast notification when the first code reference is found.
* The user will only ever see a single notification of this behavior.
* Displays the output panel on notification ack.
*/
export function notify(accessor: ServicesAccessor) {
const extension = accessor.get(IVSCodeExtensionContext);
const instantiationService = accessor.get(IInstantiationService);
const didNotify = extension.globalState.get<boolean>(CodeReferenceKey);
if (didNotify) {
return;
}
const notificationSender = accessor.get(ICompletionsNotificationSender);
const messageItems = [{ title: MatchAction }, { title: SettingAction }];
void notificationSender.showWarningMessage(matchCodeMessage, ...messageItems).then(async action => {
const event = { instantiationService, actor: 'user' as TelemetryActor };
switch (action?.title) {
case MatchAction: {
matchNotificationTelemetry.handleDoAction(event);
await commands.executeCommand(OutputPaneShowCommand);
break;
}
case SettingAction: {
await env.openExternal(Uri.parse('https://aka.ms/github-copilot-settings'));
break;
}
case undefined: {
matchNotificationTelemetry.handleDismiss(event);
break;
}
}
});
return extension.globalState.update(CodeReferenceKey, true);
}
@@ -1,102 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { window, type OutputChannel } from 'vscode';
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { Disposable, IDisposable, MutableDisposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { CopilotToken } from '../../../lib/src/auth/copilotTokenManager';
import { onCopilotToken } from '../../../lib/src/auth/copilotTokenNotifier';
interface GitHubLogger extends Disposable {
info(...messages: string[]): void;
forceShow(): void;
}
export const citationsChannelName = 'GitHub Copilot Log (Code References)';
// Literally taken from VS Code
function getCurrentTimestamp() {
const toTwoDigits = (v: number) => (v < 10 ? `0${v}` : v);
const toThreeDigits = (v: number) => (v < 10 ? `00${v}` : v < 100 ? `0${v}` : v);
const currentTime = new Date();
return `${currentTime.getFullYear()}-${toTwoDigits(currentTime.getMonth() + 1)}-${toTwoDigits(
currentTime.getDate()
)} ${toTwoDigits(currentTime.getHours())}:${toTwoDigits(currentTime.getMinutes())}:${toTwoDigits(
currentTime.getSeconds()
)}.${toThreeDigits(currentTime.getMilliseconds())}`;
}
class CodeReferenceOutputChannel implements IDisposable {
constructor(private output: OutputChannel) { }
info(...messages: string[]) {
this.output.appendLine(`${getCurrentTimestamp()} [info] ${messages.join(' ')}`);
}
show(preserveFocus: boolean) {
this.output.show(preserveFocus);
}
dispose() {
this.output.dispose();
}
}
export class GitHubCopilotLogger extends Disposable implements GitHubLogger {
private output = this._register(new MutableDisposable<CodeReferenceOutputChannel>());
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IAuthenticationService authenticationService: IAuthenticationService
) {
super();
this._register(onCopilotToken(authenticationService, t => this.checkCopilotToken(t)));
this.createChannel();
}
private checkCopilotToken = (token: Omit<CopilotToken, 'token'>) => {
if (token.codeQuoteEnabled) {
this.createChannel();
} else {
this.removeChannel();
}
};
private log(type: 'info', ...messages: string[]) {
const output = this.createChannel();
const [base, ...rest] = messages;
output[type](base, ...rest);
}
info(...messages: string[]) {
this.log('info', ...messages);
}
forceShow() {
// Preserve focus in the editor
this.getChannel()?.show(true);
}
private createChannel(): CodeReferenceOutputChannel {
if (this.output.value) {
return this.output.value;
}
this.output.value = new CodeReferenceOutputChannel(window.createOutputChannel(citationsChannelName, 'code-referencing'));
return this.output.value;
}
private getChannel(): CodeReferenceOutputChannel | undefined {
return this.output.value;
}
private removeChannel() {
this.output.value = undefined;
}
}
@@ -1,101 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { TextEditor } from 'vscode';
import { DisposableStore } from '../../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService, ServicesAccessor } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { withInMemoryTelemetry } from '../../../../lib/src/test/telemetry';
import { createExtensionTestingContext } from '../../test/context';
import { CodeRefEngagementTracker } from '../codeReferenceEngagementTracker';
import { citationsChannelName } from '../outputChannel';
suite('CodeReferenceEngagementTracker', function () {
let engagementTracker: CodeRefEngagementTracker;
let accessor: ServicesAccessor;
const disposables = new DisposableStore();
setup(function () {
accessor = createExtensionTestingContext().createTestingAccessor();
engagementTracker = disposables.add(accessor.get(IInstantiationService).createInstance(CodeRefEngagementTracker));
});
teardown(function () {
disposables.clear();
});
test('sends a telemetry event when the output channel is focused', async function () {
const telemetry = await withInMemoryTelemetry(accessor, () => {
engagementTracker.onActiveEditorChange({
document: { uri: { scheme: 'output', path: citationsChannelName } },
} as TextEditor);
});
assert.ok(telemetry.reporter.events.length === 1);
assert.strictEqual(telemetry.reporter.events[0].name, 'code_referencing.github_copilot_log.focus.count');
});
test('sends a telemetry event when the output channel is focused2', async function () {
const telemetry = await withInMemoryTelemetry(accessor, () => {
engagementTracker.onActiveEditorChange({
document: { uri: { scheme: 'output', path: citationsChannelName } },
} as TextEditor);
});
assert.ok(telemetry.reporter.events.length === 1);
assert.strictEqual(telemetry.reporter.events[0].name, 'code_referencing.github_copilot_log.focus.count');
});
test('sends a telemetry event when the output channel is opened', async function () {
const telemetry = await withInMemoryTelemetry(accessor, () => {
engagementTracker.onVisibleEditorsChange([
{
document: { uri: { scheme: 'output', path: citationsChannelName } },
},
] as TextEditor[]);
});
assert.ok(telemetry.reporter.events.length === 1);
assert.strictEqual(telemetry.reporter.events[0].name, 'code_referencing.github_copilot_log.open.count');
});
test('does not send a telemetry event when the output channel is already opened', async function () {
const telemetry = await withInMemoryTelemetry(accessor, () => {
engagementTracker.onVisibleEditorsChange([
{
document: { uri: { scheme: 'output', path: citationsChannelName } },
},
] as TextEditor[]);
engagementTracker.onVisibleEditorsChange([
{
document: { uri: { scheme: 'output', path: citationsChannelName } },
},
{
document: { uri: { scheme: 'file', path: 'some-other-file.js' } },
},
] as TextEditor[]);
});
assert.ok(telemetry.reporter.events.length === 1);
});
test('tracks when the log closes internally', async function () {
const telemetry = await withInMemoryTelemetry(accessor, () => {
engagementTracker.onVisibleEditorsChange([
{
document: { uri: { scheme: 'output', path: citationsChannelName } },
},
] as TextEditor[]);
engagementTracker.onVisibleEditorsChange([
{
document: { uri: { scheme: 'file', path: 'some-other-file.js' } },
},
] as TextEditor[]);
});
assert.ok(telemetry.reporter.events.length === 1);
assert.ok(engagementTracker.logVisible === false);
});
});
@@ -1,70 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as Sinon from 'sinon';
import { Disposable, ExtensionContext } from 'vscode';
import { CodeReference } from '..';
import { CopilotToken, createTestExtendedTokenInfo } from '../../../../../../../platform/authentication/common/copilotToken';
import { generateUuid } from '../../../../../../../util/vs/base/common/uuid';
import { IInstantiationService } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { ConnectionState } from '../../../../lib/src/snippy/connectionState';
import { createExtensionTestingContext } from '../../test/context';
function testExtensionContext() {
return {
subscriptions: [],
};
}
suite('CodeReference', function () {
let extensionContext: ExtensionContext;
let instantiationService: IInstantiationService;
let sub: Disposable | undefined;
setup(function () {
const accessor = createExtensionTestingContext().createTestingAccessor();
instantiationService = accessor.get(IInstantiationService);
extensionContext = testExtensionContext() as unknown as ExtensionContext;
});
teardown(function () {
extensionContext.subscriptions.forEach(sub => {
sub.dispose();
});
sub?.dispose();
ConnectionState.setDisabled();
});
suite('subscriptions', function () {
test('should be undefined by default', function () {
const result = instantiationService.createInstance(CodeReference);
sub = result.subscriptions;
assert.ok(!sub);
});
test('should be updated correctly when token change events received', function () {
const codeQuote = instantiationService.createInstance(CodeReference);
const enabledToken = new CopilotToken(createTestExtendedTokenInfo({ token: `test token ${generateUuid()}`, username: 'fixedTokenManager', copilot_plan: 'unknown', code_quote_enabled: true }));
const disabledToken = new CopilotToken(createTestExtendedTokenInfo({ token: `test token ${generateUuid()}`, username: 'fixedTokenManager', copilot_plan: 'unknown', code_quote_enabled: false }));
codeQuote.onCopilotToken(enabledToken);
assert.ok(codeQuote.enabled);
assert.ok(codeQuote.subscriptions);
assert.ok(codeQuote.subscriptions instanceof Disposable);
const subSpy = Sinon.spy(codeQuote.subscriptions, 'dispose');
codeQuote.onCopilotToken(disabledToken);
assert.ok(!codeQuote.enabled);
assert.strictEqual(codeQuote.subscriptions, undefined);
assert.strictEqual(subSpy.calledOnce, true);
codeQuote.onCopilotToken(enabledToken);
assert.ok(codeQuote.enabled);
assert.notStrictEqual(codeQuote.subscriptions, undefined);
});
});
});
@@ -1,121 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import sinon from 'sinon';
import { commands, env } from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../../platform/extContext/common/extensionContext';
import { IInstantiationService, ServicesAccessor } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { ICompletionsNotificationSender } from '../../../../lib/src/notificationSender';
import { OutputPaneShowCommand } from '../../../../lib/src/snippy/constants';
import { withInMemoryTelemetry } from '../../../../lib/src/test/telemetry';
import { TestNotificationSender } from '../../../../lib/src/test/testHelpers';
import { createExtensionTestingContext } from '../../test/context';
import { notify } from '../matchNotifier';
suite('.match', function () {
let accessor: ServicesAccessor;
setup(function () {
accessor = createExtensionTestingContext().createTestingAccessor();
});
test('populates the globalState object', async function () {
const extensionContext = accessor.get(IVSCodeExtensionContext);
const globalState = extensionContext.globalState;
await notify(accessor);
assert.ok(globalState.get('codeReference.notified'));
});
test('notifies the user', async function () {
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performAction('View reference');
await notify(accessor);
assert.strictEqual(testNotificationSender.sentMessages.length, 1);
});
test('sends a telemetry event on view reference action', async function () {
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performAction('View reference');
const telemetry = await withInMemoryTelemetry(accessor, async accessor => {
await notify(accessor);
});
assert.strictEqual(telemetry.reporter.events.length, 1);
assert.strictEqual(telemetry.reporter.events[0].name, 'code_referencing.match_notification.acknowledge.count');
});
test('executes the output panel display command on view reference action', async function () {
const spy = sinon.spy(commands, 'executeCommand');
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performAction('View reference');
await notify(accessor);
await testNotificationSender.waitForMessages();
assert.ok(spy.calledOnce);
assert.ok(spy.calledWith(OutputPaneShowCommand));
spy.restore();
});
test('opens the settings page on change setting action', async function () {
const stub = sinon.stub(env, 'openExternal');
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performAction('Change setting');
await notify(accessor);
await testNotificationSender.waitForMessages();
assert.ok(stub.calledOnce);
assert.ok(
stub.calledWith(
sinon.match({
scheme: 'https',
authority: 'aka.ms',
path: '/github-copilot-settings',
})
)
);
stub.restore();
});
test('sends a telemetry event on notification dismissal', async function () {
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performDismiss();
const telemetry = await withInMemoryTelemetry(accessor, async accessor => {
await notify(accessor);
});
await testNotificationSender.waitForMessages();
assert.strictEqual(telemetry.reporter.events.length, 1);
assert.strictEqual(telemetry.reporter.events[0].name, 'code_referencing.match_notification.ignore.count');
});
test('does not notify if already notified', async function () {
const extensionContext = accessor.get(IVSCodeExtensionContext);
const instantiationService = accessor.get(IInstantiationService);
const globalState = extensionContext.globalState;
const testNotificationSender = accessor.get(ICompletionsNotificationSender) as TestNotificationSender;
testNotificationSender.performAction('View reference');
await globalState.update('codeReference.notified', true);
await instantiationService.invokeFunction(notify);
await testNotificationSender.waitForMessages();
assert.strictEqual(testNotificationSender.sentMessages.length, 0);
});
});
@@ -1,10 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSCodeWorkspace } from '../../../../inlineEdits/vscode-node/parts/vscodeWorkspace';
import { ICompletionsObservableWorkspace } from '../../lib/src/completionsObservableWorkspace';
export class CompletionsObservableWorkspace extends VSCodeWorkspace implements ICompletionsObservableWorkspace {
declare _serviceBrand: undefined;
}
@@ -1,249 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { WorkspaceConfiguration } from 'vscode';
import * as vscode from 'vscode';
import { IInstantiationService, ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import {
ConfigKey,
ConfigKeyType,
ConfigProvider, getConfigDefaultForKey,
getConfigKeyRecursively,
getOptionalConfigDefaultForKey,
ICompletionsConfigProvider,
ICompletionsEditorAndPluginInfo,
packageJson
} from '../../lib/src/config';
import { CopilotConfigPrefix } from '../../lib/src/constants';
import { Logger } from '../../lib/src/logger';
import { transformEvent } from '../../lib/src/util/event';
const logger = new Logger('extensionConfig');
export class VSCodeConfigProvider extends ConfigProvider {
private config: WorkspaceConfiguration;
constructor() {
super();
this.config = vscode.workspace.getConfiguration(CopilotConfigPrefix);
// Reload cached config if a workspace config change effects Copilot namespace
vscode.workspace.onDidChangeConfiguration(changeEvent => {
if (changeEvent.affectsConfiguration(CopilotConfigPrefix)) {
this.config = vscode.workspace.getConfiguration(CopilotConfigPrefix);
}
});
}
override getConfig<T>(key: ConfigKeyType): T {
return getConfigKeyRecursively<T>(this.config, key) ?? getConfigDefaultForKey(key);
}
override getOptionalConfig<T>(key: ConfigKeyType): T | undefined {
return getConfigKeyRecursively<T>(this.config, key) ?? getOptionalConfigDefaultForKey(key);
}
// Dumps config settings defined in the extension json
override dumpForTelemetry(): { [key: string]: string } {
return {};
}
override onDidChangeCopilotSettings: ConfigProvider['onDidChangeCopilotSettings'] = transformEvent(
vscode.workspace.onDidChangeConfiguration,
event => {
if (event.affectsConfiguration('github.copilot')) {
return this;
}
if (event.affectsConfiguration('github.copilot-chat')) {
return this;
}
}
);
}
// From vscode's src/vs/platform/telemetry/common/telemetryUtils.ts
const telemetryAllowedAuthorities = new Set([
'ssh-remote',
'dev-container',
'attached-container',
'wsl',
'tunnel',
'codespaces',
'amlext',
]);
export class VSCodeEditorInfo implements ICompletionsEditorAndPluginInfo {
declare _serviceBrand: undefined;
getEditorInfo() {
let devName = vscode.env.uriScheme;
if (vscode.version.endsWith('-insider')) {
devName = devName.replace(/-insiders$/, '');
}
const remoteName = vscode.env.remoteName;
if (remoteName) {
devName += `@${telemetryAllowedAuthorities.has(remoteName) ? remoteName : 'other'}`;
}
return {
name: 'vscode',
readableName: vscode.env.appName.replace(/ - Insiders$/, ''),
devName: devName,
version: vscode.version,
root: vscode.env.appRoot,
};
}
getEditorPluginInfo() {
return { name: 'copilot-chat', readableName: 'GitHub Copilot for Visual Studio Code', version: packageJson.version };
}
getRelatedPluginInfo() {
// Any additions to this list should also be added as a known filter in
// lib/src/experiments/filters.ts
return [
'ms-vscode.cpptools',
'ms-vscode.cmake-tools',
'ms-vscode.makefile-tools',
'ms-dotnettools.csdevkit',
'ms-python.python',
'ms-python.vscode-pylance',
'vscjava.vscode-java-pack',
'vscjava.vscode-java-dependency',
'vscode.typescript-language-features',
'ms-vscode.vscode-typescript-next',
'ms-dotnettools.csharp',
'github.copilot-chat',
]
.map(name => {
const extpj = vscode.extensions.getExtension(name)?.packageJSON as unknown;
if (extpj && typeof extpj === 'object' && 'version' in extpj && typeof extpj.version === 'string') {
return { name, version: extpj.version };
}
})
.filter(plugin => plugin !== undefined);
}
}
type EnabledConfigKeyType = { [key: string]: boolean };
function getEnabledConfigObject(accessor: ServicesAccessor): EnabledConfigKeyType {
const configProvider = accessor.get(ICompletionsConfigProvider);
return { '*': true, ...(configProvider.getConfig<EnabledConfigKeyType>(ConfigKey.Enable) ?? {}) };
}
function getEnabledConfig(accessor: ServicesAccessor, languageId: string): boolean {
const obj = getEnabledConfigObject(accessor);
return obj[languageId] ?? obj['*'] ?? true;
}
/**
* Checks if automatic completions are enabled for the current document by all Copilot completion settings.
* Excludes the `editor.inlineSuggest.enabled` setting.
* Return undefined if there is no current document.
*/
export function isCompletionEnabled(accessor: ServicesAccessor): boolean | undefined {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return undefined;
}
return isCompletionEnabledForDocument(accessor, editor.document);
}
export function isCompletionEnabledForDocument(accessor: ServicesAccessor, document: vscode.TextDocument): boolean {
return getEnabledConfig(accessor, document.languageId);
}
export function isInlineSuggestEnabled(): boolean | undefined {
return vscode.workspace.getConfiguration('editor.inlineSuggest').get<boolean>('enabled');
}
type ConfigurationInspect = Exclude<ReturnType<vscode.WorkspaceConfiguration['inspect']>, undefined>;
const inspectKinds: [keyof ConfigurationInspect, vscode.ConfigurationTarget, boolean][] = [
['workspaceFolderLanguageValue', vscode.ConfigurationTarget.WorkspaceFolder, true],
['workspaceFolderValue', vscode.ConfigurationTarget.WorkspaceFolder, false],
['workspaceLanguageValue', vscode.ConfigurationTarget.Workspace, true],
['workspaceValue', vscode.ConfigurationTarget.Workspace, false],
['globalLanguageValue', vscode.ConfigurationTarget.Global, true],
['globalValue', vscode.ConfigurationTarget.Global, false],
];
function getConfigurationTargetForEnabledConfig(): vscode.ConfigurationTarget {
const inspect = vscode.workspace.getConfiguration(CopilotConfigPrefix).inspect(ConfigKey.Enable);
if (inspect?.workspaceFolderValue !== undefined) {
return vscode.ConfigurationTarget.WorkspaceFolder;
} else if (inspect?.workspaceValue !== undefined) {
return vscode.ConfigurationTarget.Workspace;
} else {
return vscode.ConfigurationTarget.Global;
}
}
/**
* Enable completions by every means possible.
*/
export async function enableCompletions(accessor: ServicesAccessor) {
const instantiationService = accessor.get(IInstantiationService);
const scope = vscode.window.activeTextEditor?.document;
// Make sure both of these settings are enabled, because that's a precondition for the user seeing inline completions.
for (const [section, option] of [['', 'editor.inlineSuggest.enabled']]) {
const config = vscode.workspace.getConfiguration(section, scope);
const inspect = config.inspect(option);
// Start from the most specific setting and work our way up to the global default.
for (const [key, target, overrideInLanguage] of inspectKinds) {
// Exit condition: if VS Code thinks the setting is enabled, we're done.
// This might be true from the start, or a call to .update() might flip it.
if (vscode.workspace.getConfiguration(section, scope).get(option)) {
break;
}
if (inspect?.[key] === false) {
await config.update(option, true, target, overrideInLanguage);
}
}
}
// The rest of this function is the inverse of disableCompletions(), updating the github.copilot.enable setting.
const languageId = vscode.window.activeTextEditor?.document.languageId;
if (!languageId) { return; }
const config = vscode.workspace.getConfiguration(CopilotConfigPrefix);
const enabledConfig = { ...instantiationService.invokeFunction(getEnabledConfigObject) };
if (!(languageId in enabledConfig)) {
enabledConfig['*'] = true;
} else {
enabledConfig[languageId] = true;
}
await config.update(ConfigKey.Enable, enabledConfig, getConfigurationTargetForEnabledConfig());
if (!instantiationService.invokeFunction(isCompletionEnabled)) {
const inspect = vscode.workspace.getConfiguration(CopilotConfigPrefix).inspect(ConfigKey.Enable);
const error = new Error(`Failed to enable completions for ${languageId}: ${JSON.stringify(inspect)}`);
instantiationService.invokeFunction(acc => logger.exception(acc, error, '.enable'));
}
}
/**
* Disable completions using the github.copilot.enable setting.
*/
export async function disableCompletions(accessor: ServicesAccessor) {
const instantiationService = accessor.get(IInstantiationService);
const languageId = vscode.window.activeTextEditor?.document.languageId;
if (!languageId) { return; }
const config = vscode.workspace.getConfiguration(CopilotConfigPrefix);
const enabledConfig = { ...instantiationService.invokeFunction(getEnabledConfigObject) };
if (!(languageId in enabledConfig)) {
enabledConfig['*'] = false;
} else if (enabledConfig[languageId]) {
enabledConfig[languageId] = false;
}
await config.update(ConfigKey.Enable, enabledConfig, getConfigurationTargetForEnabledConfig());
if (instantiationService.invokeFunction(isCompletionEnabled)) {
const inspect = vscode.workspace.getConfiguration(CopilotConfigPrefix).inspect(ConfigKey.Enable);
const error = new Error(`Failed to disable completions for ${languageId}: ${JSON.stringify(inspect)}`);
instantiationService.invokeFunction(acc => logger.exception(acc, error, '.disable'));
}
}
export async function toggleCompletions(accessor: ServicesAccessor) {
if (isCompletionEnabled(accessor) && isInlineSuggestEnabled()) {
await disableCompletions(accessor);
} else {
await enableCompletions(accessor);
}
}
@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Commands ending with "Client" refer to the command ID used in the legacy Copilot extension.
// - These IDs should not appear in the package.json file
// - These IDs should be registered to support all functionality (except if this command needs to be supported when both extensions are loaded/active).
// Commands ending with "Chat" refer to the command ID used in the Copilot Chat extension.
// - These IDs should be used in package.json
// - These IDs should only be registered if they appear in the package.json (meaning the command palette) or if the command needs to be supported when both extensions are loaded/active.
export const CMDOpenPanelClient = 'github.copilot.generate';
export const CMDOpenPanelChat = 'github.copilot.chat.openSuggestionsPanel'; // "github.copilot.chat.generate" is already being used
export const CMDAcceptCursorPanelSolutionClient = 'github.copilot.acceptCursorPanelSolution';
export const CMDNavigatePreviousPanelSolutionClient = 'github.copilot.previousPanelSolution';
export const CMDNavigateNextPanelSolutionClient = 'github.copilot.nextPanelSolution';
export const CMDToggleStatusMenuClient = 'github.copilot.toggleStatusMenu';
export const CMDToggleStatusMenuChat = 'github.copilot.chat.toggleStatusMenu';
// Needs to be supported in both extensions when they are loaded/active. Requires a different ID.
export const CMDSendCompletionsFeedbackChat = 'github.copilot.chat.sendCompletionFeedback';
export const CMDEnableCompletionsChat = 'github.copilot.chat.completions.enable';
export const CMDDisableCompletionsChat = 'github.copilot.chat.completions.disable';
export const CMDToggleCompletionsChat = 'github.copilot.chat.completions.toggle';
export const CMDEnableCompletionsClient = 'github.copilot.completions.enable';
export const CMDDisableCompletionsClient = 'github.copilot.completions.disable';
export const CMDToggleCompletionsClient = 'github.copilot.completions.toggle';
export const CMDOpenLogsClient = 'github.copilot.openLogs';
export const CMDOpenDocumentationClient = 'github.copilot.openDocs';
// Existing chat command reused for diagnostics
export const CMDCollectDiagnosticsChat = 'github.copilot.debug.collectDiagnostics';
// Context variable that enable/disable panel-specific commands
export const CopilotPanelVisible = 'github.copilot.panelVisible';
export const ComparisonPanelVisible = 'github.copilot.comparisonPanelVisible';
export const CMDOpenModelPickerClient = 'github.copilot.openModelPicker';
export const CMDOpenModelPickerChat = 'github.copilot.chat.openModelPicker';
@@ -1,28 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { languages, workspace } from 'vscode';
import { DocumentSelector } from 'vscode-languageserver-protocol';
import { IInstantiationService } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { isDocumentValid } from '../../lib/src/util/documentEvaluation';
import { DocumentContext } from '../../types/src';
export async function contextProviderMatch(
instantiationService: IInstantiationService,
documentSelector: DocumentSelector,
documentContext: DocumentContext
): Promise<number> {
const vscDoc = workspace.textDocuments.find(td => td.uri.toString() === documentContext.uri);
if (!vscDoc) {
return 0;
}
const result = await instantiationService.invokeFunction(isDocumentValid, documentContext);
if (result.status !== 'valid') {
return 0;
}
return languages.match(documentSelector, vscDoc);
}
@@ -1,83 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Command, commands, InlineCompletionItem, Uri } from 'vscode';
import { Disposable } from '../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService, ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { collectCompletionDiagnostics, formatDiagnosticsAsMarkdown } from '../../lib/src/diagnostics';
import { telemetry, TelemetryData } from '../../lib/src/telemetry';
import { CMDSendCompletionsFeedbackChat } from './constants';
export const sendCompletionFeedbackCommand: Command = {
command: CMDSendCompletionsFeedbackChat,
title: 'Send Copilot Completion Feedback',
tooltip: 'Send feedback about the last shown Copilot completion item',
};
export class CopilotCompletionFeedbackTracker extends Disposable {
private lastShownCopilotCompletionItem: InlineCompletionItem | undefined;
constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) {
super();
this._register(commands.registerCommand(sendCompletionFeedbackCommand.command, async () => {
const commandArg: unknown = this.lastShownCopilotCompletionItem?.command?.arguments?.[0];
let telemetryArg: TelemetryData | undefined;
if (commandArg && typeof commandArg === 'object' && 'telemetry' in commandArg) {
if (commandArg.telemetry instanceof TelemetryData) {
telemetryArg = commandArg.telemetry;
}
}
this.instantiationService.invokeFunction(telemetry, 'ghostText.sentFeedback', telemetryArg);
await this.instantiationService.invokeFunction(openGitHubIssue, this.lastShownCopilotCompletionItem, telemetryArg);
}));
}
trackItem(item: InlineCompletionItem) {
this.lastShownCopilotCompletionItem = item;
}
}
async function openGitHubIssue(
accessor: ServicesAccessor,
item: InlineCompletionItem | undefined,
telemetry: TelemetryData | undefined
) {
const body = generateGitHubIssueBody(accessor, item, telemetry);
await commands.executeCommand('workbench.action.openIssueReporter', {
extensionId: 'github.copilot',
uri: Uri.parse('https://github.com/microsoft/vscode'),
data: body,
});
}
function generateGitHubIssueBody(
accessor: ServicesAccessor,
item: InlineCompletionItem | undefined,
telemetry: TelemetryData | undefined
) {
const diagnostics = collectCompletionDiagnostics(accessor, telemetry);
const formattedDiagnostics = formatDiagnosticsAsMarkdown(diagnostics);
if (typeof item?.insertText !== 'string') {
return '';
}
return `## Copilot Completion Feedback
### Describe the issue, feedback, or steps to reproduce it:
### Completion text:
\`\`\`
${item.insertText}
\`\`\`
<details>
<summary>Diagnostics</summary>
${formattedDiagnostics}
</details>
`;
}
@@ -1,65 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Range, commands, window, type Disposable } from 'vscode';
import { CopilotNamedAnnotationList } from '../../../../../../platform/completions-core/common/openai/copilotAnnotations';
import { DisposableStore, IDisposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService, type ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import * as constants from '../constants';
import { registerCommand } from '../telemetry';
import { wrapDoc } from '../textDocumentManager';
import { CopilotSuggestionsPanelManager } from './copilotSuggestionsPanelManager';
// Exported for testing
export enum PanelNavigationType {
Previous = 'previous',
Next = 'next',
}
/**
* This interface contains data associated to a completion displayed in the panel.
*/
export interface PanelCompletion {
insertText: string;
range: Range;
copilotAnnotations?: CopilotNamedAnnotationList;
postInsertionCallback: () => PromiseLike<void> | void;
}
export function registerPanelSupport(accessor: ServicesAccessor): Disposable {
const instantiationService = accessor.get(IInstantiationService);
const suggestionsPanelManager = instantiationService.createInstance(CopilotSuggestionsPanelManager);
const disposableStore = new DisposableStore();
function registerOpenPanelCommand(id: string): IDisposable {
return registerCommand(accessor, id, async () => {
// hide ghost text while opening the generation ui
await commands.executeCommand('editor.action.inlineSuggest.hide');
await instantiationService.invokeFunction(commandOpenPanel, suggestionsPanelManager);
});
}
// Register both commands to also support command palette
disposableStore.add(registerOpenPanelCommand(constants.CMDOpenPanelChat));
disposableStore.add(registerOpenPanelCommand(constants.CMDOpenPanelClient));
// No command palette support needed for these commands
disposableStore.add(suggestionsPanelManager.registerCommands());
return disposableStore;
}
function commandOpenPanel(accessor: ServicesAccessor, suggestionsPanelManager: CopilotSuggestionsPanelManager) {
const editor = window.activeTextEditor;
if (!editor) { return; }
const wrapped = wrapDoc(editor.document);
if (!wrapped) { return; }
const { line, character } = editor.selection.active;
suggestionsPanelManager.renderPanel(editor.document, { line, character }, wrapped);
return commands.executeCommand('setContext', constants.CopilotPanelVisible, true);
}
@@ -1,49 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { IPosition, ITextDocument } from '../../../lib/src/textDocument';
import { solutionCountTarget } from '../lib/copilotPanel/common';
import { runSolutions } from '../lib/copilotPanel/panel';
import { UnformattedSolution } from '../lib/panelShared/panelTypes';
import { BaseListDocument } from '../panelShared/baseListDocument';
import { BasePanelCompletion, ISuggestionsPanel } from '../panelShared/basePanelTypes';
import { PanelCompletion } from './common';
/**
* Class representing a Open Copilot list using a ITextDocument as a way of displaying results.
* Currently only used in the VSCode extension.
*/
export class CopilotListDocument extends BaseListDocument<PanelCompletion> {
constructor(
textDocument: ITextDocument,
position: IPosition,
panel: ISuggestionsPanel,
countTarget = solutionCountTarget,
@IInstantiationService instantiationService: IInstantiationService
) {
super(textDocument, position, panel, countTarget, instantiationService);
}
protected createPanelCompletion(
unformatted: UnformattedSolution,
baseCompletion: BasePanelCompletion
): PanelCompletion {
return {
insertText: baseCompletion.insertText,
range: baseCompletion.range,
copilotAnnotations: baseCompletion.copilotAnnotations,
postInsertionCallback: baseCompletion.postInsertionCallback,
};
}
protected shouldAddSolution(newItem: PanelCompletion): boolean {
return !this.findDuplicateSolution(newItem);
}
protected runSolutionsImpl(): Promise<void> {
return this.instantiationService.invokeFunction(runSolutions, this, this);
}
}
@@ -1,53 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TextDocument, WebviewPanel } from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../platform/extContext/common/extensionContext';
import { BaseSuggestionsPanel, SolutionContent, WebviewMessage } from '../panelShared/baseSuggestionsPanel';
import { PanelCompletion } from './common';
import { CopilotSuggestionsPanelManager } from './copilotSuggestionsPanelManager';
import { copilotPanelConfig } from './panelConfig';
export interface CopilotSolutionsMessage {
command: 'solutionsUpdated';
solutions: SolutionContent[];
percentage: number;
}
export class CopilotSuggestionsPanel extends BaseSuggestionsPanel<PanelCompletion> {
constructor(
webviewPanel: WebviewPanel,
document: TextDocument,
suggestionsPanelManager: CopilotSuggestionsPanelManager,
@IVSCodeExtensionContext contextService: IVSCodeExtensionContext,
) {
super(webviewPanel, document, suggestionsPanelManager, copilotPanelConfig, contextService);
}
protected renderSolutionContent(item: PanelCompletion, baseContent: SolutionContent): SolutionContent {
// Copilot panel just returns the base content without modifications
return baseContent;
}
protected createSolutionsMessage(content: SolutionContent[], percentage: number): CopilotSolutionsMessage {
return {
command: 'solutionsUpdated',
solutions: content,
percentage,
};
}
protected override async handleCustomMessage(message: WebviewMessage): Promise<boolean> {
switch (message.command) {
case 'acceptSolution': {
const solution = this.items()[message.solutionIndex];
await this.acceptSolution(solution, true);
return Promise.resolve(true);
}
default:
return Promise.resolve(false);
}
}
}
@@ -1,40 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TextDocument, WebviewPanel } from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../platform/extContext/common/extensionContext';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { IPosition, ITextDocument } from '../../../lib/src/textDocument';
import { solutionCountTarget } from '../lib/copilotPanel/common';
import { BaseSuggestionsPanelManager, ListDocumentInterface } from '../panelShared/baseSuggestionsPanelManager';
import { PanelCompletion } from './common';
import { CopilotListDocument } from './copilotListDocument';
import { CopilotSuggestionsPanel } from './copilotSuggestionsPanel';
import { copilotPanelConfig } from './panelConfig';
export class CopilotSuggestionsPanelManager extends BaseSuggestionsPanelManager<PanelCompletion> {
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IVSCodeExtensionContext extensionContext: IVSCodeExtensionContext,
) {
super(copilotPanelConfig, instantiationService, extensionContext);
}
protected createListDocument(
wrapped: ITextDocument,
position: IPosition,
panel: CopilotSuggestionsPanel
): ListDocumentInterface {
return this._instantiationService.createInstance(CopilotListDocument, wrapped, position, panel, solutionCountTarget);
}
protected createSuggestionsPanel(
panel: WebviewPanel,
document: TextDocument,
manager: this
): CopilotSuggestionsPanel {
return this._instantiationService.createInstance(CopilotSuggestionsPanel, panel, document, manager);
}
}
@@ -1,23 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as constants from '../constants';
import { CopilotPanelVisible } from '../constants';
import { PanelConfig } from '../panelShared/basePanelTypes';
// Configuration for the GitHub Copilot Suggestions Panel
export const copilotPanelConfig: PanelConfig = {
panelTitle: 'GitHub Copilot Suggestions',
webviewId: 'GitHub Copilot Suggestions',
webviewScriptName: 'suggestionsPanelWebview.js',
contextVariable: CopilotPanelVisible,
commands: {
accept: constants.CMDAcceptCursorPanelSolutionClient,
navigatePrevious: constants.CMDNavigatePreviousPanelSolutionClient,
navigateNext: constants.CMDNavigateNextPanelSolutionClient,
},
renderingMode: 'streaming',
shuffleSolutions: false,
};
@@ -1,166 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { provideVSCodeDesignSystem, vsCodeButton } from '@vscode/webview-ui-toolkit';
import DOMPurify from 'dompurify';
const solutionsContainer = document.getElementById('solutionsContainer');
const vscode = acquireVsCodeApi();
let currentFocusIndex: number = 0;
let solutionEventHandlersInitialized = false;
provideVSCodeDesignSystem().register(vsCodeButton());
type Message = {
command: string;
solutions: {
htmlSnippet: string;
citation?: {
message: string;
url: string;
};
}[];
percentage: number;
};
window.addEventListener('DOMContentLoaded', () => {
// Notify the extension that the webview is ready
vscode.postMessage({ command: 'webviewReady' });
initializeSolutionEventHandlers();
});
window.addEventListener('message', (event) => {
const message = event.data as Message; // The JSON data our extension sent
switch (message.command) {
case 'solutionsUpdated':
handleSolutionUpdate(message);
break;
case 'navigatePreviousSolution':
navigatePreviousSolution();
break;
case 'navigateNextSolution':
navigateNextSolution();
break;
}
});
function handleSolutionUpdate(message: Message) {
updateLoadingContainer(message);
if (solutionsContainer) {
solutionsContainer.innerHTML = message.solutions
.map((solution, index) => {
const renderedCitation = solution.citation
? `<p>
<span style="vertical-align: text-bottom" aria-hidden="true">Warning</span>
${DOMPurify.sanitize(solution.citation.message)}
<a href="${DOMPurify.sanitize(solution.citation.url)}" target="_blank">Inspect source code</a>
</p>`
: '';
const sanitizedSnippet = DOMPurify.sanitize(solution.htmlSnippet);
return `<h3 class='solutionHeading' id="solution-${index + 1}-heading">Suggestion ${index + 1}</h3>
<div class='snippetContainer' aria-labelledby="solution-${index + 1}-heading" role="group" data-solution-index="${index}">${sanitizedSnippet
}</div>
${DOMPurify.sanitize(renderedCitation)}
<vscode-button role="button" class="acceptButton" id="acceptButton${index}" appearance="secondary" data-solution-index="${index}">Accept suggestion ${index + 1
}</vscode-button>`;
})
.join('');
}
}
function navigatePreviousSolution() {
const snippets = document.querySelectorAll<HTMLElement>('.snippetContainer pre');
const prevIndex = currentFocusIndex - 1;
snippets[prevIndex]?.focus();
}
function navigateNextSolution() {
const snippets = document.querySelectorAll<HTMLElement>('.snippetContainer pre');
const nextIndex = (currentFocusIndex ?? -1) + 1;
if (snippets[nextIndex]) {
snippets[nextIndex].focus();
} else if (snippets[0]) {
snippets[0].focus();
}
}
function updateLoadingContainer(message: Message) {
const progressBar = document.getElementById('progress-bar') as HTMLProgressElement;
const loadingContainer = document.getElementById('loadingContainer') as HTMLDivElement;
if (!progressBar || !loadingContainer) {
return;
}
if (message.percentage >= 100) {
loadingContainer.innerHTML = `${message.solutions.length} Suggestions`;
} else {
const loadingLabelElement = loadingContainer.querySelector('label') as HTMLLabelElement;
if (loadingLabelElement.textContent !== 'Loading suggestions:\u00A0') {
loadingLabelElement.textContent = 'Loading suggestions:\u00A0';
}
progressBar.value = message.percentage;
}
}
function initializeSolutionEventHandlers(): void {
if (solutionEventHandlersInitialized || solutionsContainer === null) {
return;
}
solutionsContainer.addEventListener('focusin', (event) => {
const target = event.target as HTMLElement | null;
const index = extractSolutionIndex(target);
if (index === undefined) {
return;
}
handleFocus(index);
});
solutionsContainer.addEventListener('click', (event) => {
const target = event.target as HTMLElement | null;
const button = target?.closest('vscode-button[data-solution-index]');
if (!(button instanceof HTMLElement)) {
return;
}
const index = extractSolutionIndex(button);
if (index === undefined) {
return;
}
handleClick(index);
});
solutionEventHandlersInitialized = true;
}
function extractSolutionIndex(element: HTMLElement | null): number | undefined {
const solutionElement = element?.closest('[data-solution-index]');
if (!(solutionElement instanceof HTMLElement)) {
return undefined;
}
const attributeValue = solutionElement.getAttribute('data-solution-index');
if (attributeValue === null) {
return undefined;
}
const index = Number.parseInt(attributeValue, 10);
return Number.isNaN(index) ? undefined : index;
}
function handleFocus(index: number) {
currentFocusIndex = index;
vscode.postMessage({
command: 'focusSolution',
solutionIndex: index,
});
}
function handleClick(index: number) {
vscode.postMessage({
command: 'acceptSolution',
solutionIndex: index,
});
}
@@ -1,22 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2022",
"skipLibCheck": true, // https://github.com/DataDog/datadog-ci/issues/1059
"sourceMap": true,
"rootDir": ".",
"lib": ["ES2021", "dom"],
// Reset values set in the parent tsconfig
"strict": true, /* enable all strict type-checking options */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noImplicitOverride": true, /* Force use of `override` keyword. */
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"useDefineForClassFields": false,
"resolveJsonModule": true,
"experimentalDecorators": true,
"isolatedModules": false,
},
"exclude": [],
}
@@ -1,27 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../util/common/services';
import { Command, StatusKind } from '../../types/src';
export const ICompletionsExtensionStatus = createServiceIdentifier<ICompletionsExtensionStatus>('ICompletionsExtensionStatus');
export interface ICompletionsExtensionStatus {
readonly _serviceBrand: undefined;
kind: StatusKind;
message?: string;
busy: boolean;
command?: Command;
}
export class CopilotExtensionStatus implements ICompletionsExtensionStatus {
declare _serviceBrand: undefined;
constructor(
public kind: StatusKind = 'Normal',
public message?: string,
public busy = false,
public command?: Command
) { }
}
@@ -1,32 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { FileType, Uri, workspace } from 'vscode';
import { FileIdentifier, FileStat, ICompletionsFileSystemService } from '../../lib/src/fileSystem';
class ExtensionFileSystem implements ICompletionsFileSystemService {
declare _serviceBrand: undefined;
async readFileString(uri: FileIdentifier): Promise<string> {
if (typeof uri !== 'string') {
uri = uri.uri;
}
return new TextDecoder().decode(await workspace.fs.readFile(Uri.parse(uri, true)));
}
async stat(uri: FileIdentifier): Promise<FileStat> {
if (typeof uri !== 'string') {
uri = uri.uri;
}
return await workspace.fs.stat(Uri.parse(uri, true));
}
async readDirectory(uri: FileIdentifier): Promise<[string, FileType][]> {
if (typeof uri !== 'string') {
uri = uri.uri;
}
return await workspace.fs.readDirectory(Uri.parse(uri, true));
}
}
export const extensionFileSystem = new ExtensionFileSystem();
@@ -1,127 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
CancellationToken,
InlineCompletionContext,
InlineCompletionEndOfLifeReason,
InlineCompletionEndOfLifeReasonKind,
InlineCompletionItem,
InlineCompletionList,
InlineCompletionTriggerKind,
PartialAcceptInfo,
Position,
Range,
TextDocument,
window
} from 'vscode';
import { ISurveyService } from '../../../../../../platform/survey/common/surveyService';
import { assertNever } from '../../../../../../util/vs/base/common/assert';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { createCorrelationId } from '../../../../../inlineEdits/common/correlationId';
import { CopilotCompletion } from '../../../lib/src/ghostText/copilotCompletion';
import { handleGhostTextPostInsert, handleGhostTextShown, handlePartialGhostTextPostInsert } from '../../../lib/src/ghostText/last';
import { GhostText } from '../../../lib/src/inlineCompletion';
import { telemetry } from '../../../lib/src/telemetry';
import { wrapDoc } from '../textDocumentManager';
export interface GhostTextCompletionList extends InlineCompletionList {
items: GhostTextCompletionItem[];
}
export interface GhostTextCompletionItem extends InlineCompletionItem {
copilotCompletion: CopilotCompletion;
}
export class GhostTextProvider {
private readonly ghostText: GhostText;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ISurveyService private readonly _surveyService: ISurveyService,
) {
this.ghostText = this.instantiationService.createInstance(GhostText);
}
async provideInlineCompletionItems(
vscodeDoc: TextDocument,
position: Position,
context: InlineCompletionContext,
token: CancellationToken
): Promise<GhostTextCompletionList | undefined> {
const textDocument = wrapDoc(vscodeDoc);
if (!textDocument) {
return;
}
// Opportunity ID is a unique ID generated by the client relating to a single "opportunity"
// to provide some kind of suggestion to the user. Multiple requests might be made for a single
// opportunity, for example requesting a completion as well as an edit suggestion. The single ID
// allows us to correlate the different requests.
const opportunityId = context.requestUuid;
const formattingOptions = window.visibleTextEditors.find(e => e.document.uri === vscodeDoc.uri)?.options;
const rawCompletions = await this.ghostText.getInlineCompletions(textDocument, position, token, {
isCycling: context.triggerKind === InlineCompletionTriggerKind.Invoke,
selectedCompletionInfo: context.selectedCompletionInfo,
formattingOptions,
opportunityId,
});
if (!rawCompletions) {
return;
}
const items: GhostTextCompletionItem[] = rawCompletions.map(completion => {
const { start, end } = completion.range;
const newRange = new Range(start.line, start.character, end.line, end.character);
return {
insertText: completion.insertText,
range: newRange,
copilotCompletion: completion,
correlationId: createCorrelationId('completions', {}),
} satisfies GhostTextCompletionItem;
});
return { items };
}
handleDidShowCompletionItem(item: GhostTextCompletionItem) {
this.instantiationService.invokeFunction(handleGhostTextShown, item.copilotCompletion);
}
handleDidPartiallyAcceptCompletionItem(item: GhostTextCompletionItem, info: number | PartialAcceptInfo) {
if (typeof info === 'number') {
return; // deprecated API
}
this.instantiationService.invokeFunction(handlePartialGhostTextPostInsert, item.copilotCompletion, info.acceptedLength);
}
async handleEndOfLifetime(completionItem: GhostTextCompletionItem, reason: InlineCompletionEndOfLifeReason) {
const copilotCompletion = completionItem.copilotCompletion;
switch (reason.kind) {
case InlineCompletionEndOfLifeReasonKind.Accepted: {
this.instantiationService.invokeFunction(handleGhostTextPostInsert, copilotCompletion);
this._surveyService.signalUsage('completions').catch(() => {
// Ignore errors from the survey command execution
});
return;
}
case InlineCompletionEndOfLifeReasonKind.Rejected: {
this.instantiationService.invokeFunction(telemetry, 'ghostText.dismissed', copilotCompletion.telemetry);
return;
}
case InlineCompletionEndOfLifeReasonKind.Ignored: {
// @ulugbekna: no-op ?
return;
}
default: {
assertNever(reason);
}
}
}
}
@@ -1,11 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export enum Icon {
Logo = '$(copilot)',
Warning = '$(copilot-warning)',
NotConnected = '$(copilot-not-connected)',
Blocked = '$(copilot-blocked)',
}
@@ -1,6 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const solutionCountTarget = 10;
@@ -1,137 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInstantiationService, type ServicesAccessor } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { asyncIterableMapFilter } from '../../../../lib/src/helpers/iterableHelpers';
import { ICompletionsLogTargetService, Logger } from '../../../../lib/src/logger';
import { CopilotUiKind, ICompletionsOpenAIFetcherService } from '../../../../lib/src/openai/fetch';
import { APIChoice } from '../../../../lib/src/openai/openai';
import { ICompletionsStatusReporter } from '../../../../lib/src/progress';
import { getNodeStartUtil } from '../../../../lib/src/prompt/parseBlock';
import { trimLastLine } from '../../../../lib/src/prompt/prompt';
import { postProcessChoiceInContext } from '../../../../lib/src/suggestions/suggestions';
import { LocationFactory } from '../../../../lib/src/textDocument';
import {
generateSolutionsStream,
reportSolutions,
setupCompletionParams,
setupPromptAndTelemetry,
SolutionManager,
trimChoices,
} from '../panelShared/common';
import { ISolutionHandler, SolutionsStream, UnformattedSolution } from '../panelShared/panelTypes';
const solutionsLogger = new Logger('solutions');
/**
* Given an `ISolutionManager` with the context of a specific "Open Copilot" request,
* initiate the generation of a stream of solutions for that request.
*/
export async function launchSolutions(accessor: ServicesAccessor, solutionManager: SolutionManager): Promise<SolutionsStream> {
const instantiationService = accessor.get(IInstantiationService);
const fetcherService = accessor.get(ICompletionsOpenAIFetcherService);
const logTarget = accessor.get(ICompletionsLogTargetService);
const position = solutionManager.targetPosition;
const document = solutionManager.textDocument;
// Setup prompt and telemetry using shared function
const promptSetup = await setupPromptAndTelemetry(accessor, solutionManager, 'open copilot', solutionsLogger);
if ('status' in promptSetup) {
// This is a SolutionsStream indicating an error occurred
return promptSetup;
}
const { prompt, trailingWs, telemetryData, repoInfo, ourRequestId } = promptSetup;
// Setup completion parameters using shared function
const { extra, postOptions, finishedCb, engineInfo } = instantiationService.invokeFunction(setupCompletionParams,
document,
position,
prompt,
solutionManager,
telemetryData
);
const cancellationToken = solutionManager.cancellationToken;
const completionParams = {
prompt,
languageId: document.detectedLanguageId,
repoInfo,
ourRequestId,
engineModelId: engineInfo.modelId,
count: solutionManager.solutionCountTarget,
uiKind: CopilotUiKind.Panel,
postOptions,
headers: engineInfo.headers,
extra,
};
const res = await fetcherService.fetchAndStreamCompletions(completionParams, telemetryData.extendedBy(), finishedCb, cancellationToken);
if (res.type === 'failed' || res.type === 'canceled') {
return { status: 'FinishedWithError', error: `${res.type}: ${res.reason}` };
}
let choices: AsyncIterable<APIChoice> = res.choices;
choices = trimChoices(choices);
choices = asyncIterableMapFilter(choices, choice => instantiationService.invokeFunction(postProcessChoiceInContext, document, position, choice, false, solutionsLogger));
const solutions = asyncIterableMapFilter(choices, async (apiChoice: APIChoice) => {
let display = apiChoice.completionText;
solutionsLogger.info(logTarget, `Open Copilot completion: [${apiChoice.completionText}]`);
// For completions that can happen in any location in the middle of the code we try to find the existing code
// that should be displayed in the OpenCopilot panel so the code is nicely formatted/highlighted.
// This is not needed for implement unknown function quick fix, as it will be
// always "complete" standalone function in the location suggested by TS' extension.
const displayStartPos =
(await getNodeStartUtil(document, position, apiChoice.completionText)) ??
LocationFactory.position(position.line, 0);
const [displayBefore] = trimLastLine(document.getText(LocationFactory.range(displayStartPos, position)));
display = displayBefore + display;
let completionText = apiChoice.completionText;
if (trailingWs.length > 0 && completionText.startsWith(trailingWs)) {
completionText = completionText.substring(trailingWs.length);
}
const meanLogProb = apiChoice.meanLogProb;
const meanProb: number = meanLogProb !== undefined ? Math.exp(meanLogProb) : 0;
const solutionTelemetryData = telemetryData.extendedBy({
choiceIndex: apiChoice.choiceIndex.toString(),
});
const solution: UnformattedSolution = {
completionText,
insertText: display,
range: LocationFactory.range(displayStartPos, position),
meanProb: meanProb,
meanLogProb: meanLogProb || 0,
requestId: apiChoice.requestId,
choiceIndex: apiChoice.choiceIndex,
telemetryData: solutionTelemetryData,
copilotAnnotations: apiChoice.copilotAnnotations,
};
return solution;
});
// deliberately not awaiting so that we can return quickly
const solutionsStream = generateSolutionsStream(cancellationToken, solutions[Symbol.asyncIterator]());
return solutionsStream;
}
export async function runSolutions(
accessor: ServicesAccessor,
solutionManager: SolutionManager,
solutionHandler: ISolutionHandler
): Promise<void> {
const instantiationService = accessor.get(IInstantiationService);
const statusReporter = accessor.get(ICompletionsStatusReporter);
return statusReporter.withProgress(async () => {
const nextSolution = instantiationService.invokeFunction(launchSolutions, solutionManager);
return await reportSolutions(nextSolution, solutionHandler);
});
}
@@ -1,299 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vscode';
import { generateUuid } from '../../../../../../../util/vs/base/common/uuid';
import { IInstantiationService, type ServicesAccessor } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { createCompletionState } from '../../../../lib/src/completionState';
import { BlockMode } from '../../../../lib/src/config';
import { ICompletionsFeaturesService } from '../../../../lib/src/experiments/featuresService';
import { ICompletionsBlockModeConfig } from '../../../../lib/src/ghostText/configBlockMode';
import { ICompletionsLogTargetService, type Logger } from '../../../../lib/src/logger';
import { getEngineRequestInfo } from '../../../../lib/src/openai/config';
import { CompletionHeaders, CompletionRequestExtra, PostOptions } from '../../../../lib/src/openai/fetch';
import { APIChoice, FinishedCallback } from '../../../../lib/src/openai/openai';
import { contextIndentation, parsingBlockFinished } from '../../../../lib/src/prompt/parseBlock';
import { extractPrompt, Prompt } from '../../../../lib/src/prompt/prompt';
import { extractRepoInfoInBackground, MaybeRepoInfo } from '../../../../lib/src/prompt/repository';
import { telemetrizePromptLength, telemetry, TelemetryData, TelemetryWithExp } from '../../../../lib/src/telemetry';
import { IPosition, ITextDocument, LocationFactory, TextDocumentContents } from '../../../../lib/src/textDocument';
import { isSupportedLanguageId } from '../../../../prompt/src/parse';
import { Position } from '../../../../types/src';
import { ISolutionHandler, SolutionsStream, UnformattedSolution } from './panelTypes';
export const solutionCountTarget = 10;
export function panelPositionForDocument(document: TextDocumentContents, position: Position): IPosition {
let returnPosition = position;
const line = document.lineAt(position.line);
if (!line.isEmptyOrWhitespace) {
returnPosition = line.range.end;
}
return returnPosition;
}
/**
* Trim trailing whitespace.
*/
export async function* trimChoices(choices: AsyncIterable<APIChoice>): AsyncIterable<APIChoice> {
for await (const choice of choices) {
const choiceCopy = { ...choice };
choiceCopy.completionText = choiceCopy.completionText.trimEnd();
yield choiceCopy;
}
}
export class SolutionManager {
private _savedTelemetryData?: TelemetryWithExp | undefined;
readonly targetPosition = panelPositionForDocument(this.textDocument, this.startPosition);
constructor(
readonly textDocument: ITextDocument,
public startPosition: IPosition,
readonly cancellationToken: CancellationToken,
readonly solutionCountTarget: number
) { }
get savedTelemetryData(): TelemetryWithExp | undefined {
return this._savedTelemetryData;
}
set savedTelemetryData(data: TelemetryWithExp | undefined) {
this._savedTelemetryData = data;
}
}
export async function reportSolutions(
nextSolutionPromise: Promise<SolutionsStream>,
solutionHandler: ISolutionHandler
): Promise<void> {
const nextSolution = await nextSolutionPromise;
switch (nextSolution.status) {
case 'Solution':
await solutionHandler.onSolution(nextSolution.solution);
await reportSolutions(nextSolution.next, solutionHandler);
break;
case 'FinishedNormally':
await solutionHandler.onFinishedNormally();
break;
case 'FinishedWithError':
await solutionHandler.onFinishedWithError(nextSolution.error);
break;
}
}
export async function generateSolutionsStream(
cancellationToken: CancellationToken,
solutions: AsyncIterator<UnformattedSolution>
): Promise<SolutionsStream> {
if (cancellationToken.isCancellationRequested) {
return { status: 'FinishedWithError', error: 'Cancelled' };
}
const nextResult = await solutions.next();
if (nextResult.done === true) {
return { status: 'FinishedNormally' };
}
return {
status: 'Solution',
solution: nextResult.value,
next: generateSolutionsStream(cancellationToken, solutions),
};
}
export function normalizeCompletionText(text: string): string {
return text.replace(/\s+/g, '');
}
/**
* Result of prompt processing setup
*/
export interface PromptSetupResult {
prompt: Prompt;
trailingWs: string;
telemetryData: TelemetryWithExp;
repoInfo: MaybeRepoInfo;
ourRequestId: string;
}
/**
* Sets up prompt extraction, telemetry, and handles common error cases.
* Returns null if an error occurred that should terminate processing.
*/
export async function setupPromptAndTelemetry(
accessor: ServicesAccessor,
solutionManager: SolutionManager,
source: 'open copilot' | 'open comparison',
solutionsLogger: Logger,
engineName?: string,
comparisonRequestId?: string
): Promise<PromptSetupResult | SolutionsStream> {
const position = solutionManager.targetPosition;
const document = solutionManager.textDocument;
const repoInfo = extractRepoInfoInBackground(accessor, document.uri);
// Telemetry setup
const ourRequestId = generateUuid();
const tempTelemetry = TelemetryData.createAndMarkAsIssued(
{
headerRequestId: ourRequestId,
languageId: document.detectedLanguageId,
source,
},
{}
);
const featuresService = accessor.get(ICompletionsFeaturesService);
const instantiationService = accessor.get(IInstantiationService);
const logTarget = accessor.get(ICompletionsLogTargetService);
// Update telemetry with experiment values
solutionManager.savedTelemetryData = await featuresService
.fetchTokenAndUpdateExPValuesAndAssignments(
{ uri: document.uri, languageId: document.detectedLanguageId },
tempTelemetry
);
// Add in comparison panel specific info
if (engineName) {
solutionManager.savedTelemetryData = solutionManager.savedTelemetryData!.extendedBy({
engineName,
});
}
if (comparisonRequestId) {
solutionManager.savedTelemetryData = solutionManager.savedTelemetryData!.extendedBy({
comparisonRequestId,
});
}
// Extract prompt
const promptResponse = await instantiationService.invokeFunction(extractPrompt,
ourRequestId,
createCompletionState(document, position),
solutionManager.savedTelemetryData!
);
// Handle prompt extraction errors
if (promptResponse.type === 'copilotContentExclusion') {
return { status: 'FinishedNormally' };
}
if (promptResponse.type === 'contextTooShort') {
return { status: 'FinishedWithError', error: 'Context too short' };
}
if (promptResponse.type === 'promptCancelled') {
return { status: 'FinishedWithError', error: 'Prompt cancelled' };
}
if (promptResponse.type === 'promptTimeout') {
return { status: 'FinishedWithError', error: 'Prompt timeout' };
}
if (promptResponse.type === 'promptError') {
return { status: 'FinishedWithError', error: 'Prompt error' };
}
const prompt = promptResponse.prompt;
const trailingWs = promptResponse.trailingWs;
// Handle trailing whitespace adjustment
if (trailingWs.length > 0) {
solutionManager.startPosition = LocationFactory.position(
solutionManager.startPosition.line,
solutionManager.startPosition.character - trailingWs.length
);
}
// Update telemetry with prompt information
solutionManager.savedTelemetryData = solutionManager.savedTelemetryData!.extendedBy(
{},
{
...telemetrizePromptLength(prompt),
solutionCount: solutionManager.solutionCountTarget,
promptEndPos: document.offsetAt(position),
}
);
solutionsLogger.debug(logTarget, 'prompt:', prompt);
instantiationService.invokeFunction(telemetry, 'solution.requested', solutionManager.savedTelemetryData);
return {
prompt,
trailingWs,
telemetryData: solutionManager.savedTelemetryData,
repoInfo,
ourRequestId,
};
}
/**
* Result of completion parameters setup
*/
export interface CompletionSetupResult {
extra: CompletionRequestExtra;
postOptions: PostOptions;
finishedCb: FinishedCallback;
engineInfo: { modelId: string; headers: CompletionHeaders };
}
/**
* Sets up block mode, completion parameters, and finished callback.
*/
export function setupCompletionParams(
accessor: ServicesAccessor,
document: ITextDocument,
position: IPosition,
prompt: Prompt,
solutionManager: SolutionManager,
telemetryData: TelemetryWithExp
): CompletionSetupResult {
// Compute block mode
const blockMode = accessor.get(ICompletionsBlockModeConfig).forLanguage(document.detectedLanguageId, telemetryData);
const isSupportedLanguage = isSupportedLanguageId(document.detectedLanguageId);
const contextIndent = contextIndentation(document, position);
const extra: CompletionRequestExtra = {
language: document.detectedLanguageId,
next_indent: contextIndent.next ?? 0,
prompt_tokens: prompt.prefixTokens ?? 0,
suffix_tokens: prompt.suffixTokens ?? 0,
};
const postOptions: PostOptions = {};
if (blockMode === BlockMode.Parsing && !isSupportedLanguage) {
postOptions['stop'] = ['\n\n', '\r\n\r\n'];
}
const engineInfo = getEngineRequestInfo(accessor, telemetryData);
let finishedCb: FinishedCallback;
switch (blockMode) {
case BlockMode.Server:
// Client knows the block is done when the completion is.
finishedCb = () => undefined;
// If requested at the top-level, don't trim at all.
extra.force_indent = contextIndent.prev ?? -1;
extra.trim_by_indentation = true;
break;
case BlockMode.ParsingAndServer:
finishedCb = isSupportedLanguage
? parsingBlockFinished(document, solutionManager.startPosition)
: () => undefined;
// If requested at the top-level, don't trim at all.
extra.force_indent = contextIndent.prev ?? -1;
extra.trim_by_indentation = true;
break;
case BlockMode.Parsing:
default:
finishedCb = isSupportedLanguage
? parsingBlockFinished(document, solutionManager.startPosition)
: () => undefined;
break;
}
return {
extra,
postOptions,
finishedCb,
engineInfo,
};
}
@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CopilotNamedAnnotationList } from '../../../../../../../platform/completions-core/common/openai/copilotAnnotations';
import { RequestId } from '../../../../../../../platform/networking/common/fetch';
import { TelemetryWithExp } from '../../../../lib/src/telemetry';
import { IRange } from '../../../../lib/src/textDocument';
export interface UnformattedSolution {
/** Raw text returned by model */
completionText: string;
/** Text that should be inserted into the document, replacing the text at .range */
insertText: string;
range: IRange;
meanProb: number;
meanLogProb: number;
requestId: RequestId;
choiceIndex: number;
telemetryData: TelemetryWithExp;
copilotAnnotations?: CopilotNamedAnnotationList;
/** Optional Model ID when fetching from multiple models */
modelId?: string;
}
export interface ISolutionHandler {
onSolution(solution: UnformattedSolution): Promise<void> | void;
onFinishedNormally(): Promise<void> | void;
onFinishedWithError(error: string): Promise<void> | void;
}
/**
* A stream of solutions, ending either with 'FinishedNormally' or 'FinishedWithError'.
* This structure allows for errors to occur part way through the stream, as well as
* at the beginning.
*
* The stream is similar to an async generator, but with more information when the stream
* ends: instead of just `done` we can have `FinishedNormally` or `FinishedWithError`.
*/
export type SolutionsStream =
| { status: 'FinishedNormally' }
| { status: 'FinishedWithError'; error: string }
| { status: 'Solution'; solution: UnformattedSolution; next: Promise<SolutionsStream> };
@@ -1,148 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { env, QuickPick, QuickPickItem, QuickPickItemKind, Uri, window, workspace } from 'vscode';
import { IInstantiationService, ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { ConfigKey, getConfig } from '../../lib/src/config';
import { CopilotConfigPrefix } from '../../lib/src/constants';
import { AsyncCompletionManager, ICompletionsAsyncManagerService } from '../../lib/src/ghostText/asyncCompletions';
import { CompletionsCache, ICompletionsCacheService } from '../../lib/src/ghostText/completionsCache';
import { ICompletionsLogTargetService, Logger } from '../../lib/src/logger';
import { AvailableModelsManager, ICompletionsModelManagerService, ModelItem } from '../../lib/src/openai/model';
import { telemetry, TelemetryData } from '../../lib/src/telemetry';
const logger = new Logger('modelPicker');
interface ModelPickerItem extends Omit<ModelItem, 'preview' | 'tokenizer'>, QuickPickItem {
// Distinguish between items in the quick pick
type: 'model' | 'separator' | 'learn-more';
}
// Separator and learn-more links are always shown in the quick pick
const defaultModelPickerItems: ModelPickerItem[] = [
// Add separator after the models
{
label: '',
kind: QuickPickItemKind.Separator,
modelId: 'separator',
type: 'separator' as const,
alwaysShow: true,
},
// Add "Learn more" item at the end
{
modelId: 'learn-more',
label: 'Learn more $(link-external)',
description: '',
alwaysShow: true,
type: 'learn-more' as const,
},
];
export class ModelPickerManager {
// URL for information about Copilot models
private readonly MODELS_INFO_URL = 'https://aka.ms/CopilotCompletionsModelPickerLearnMore';
get models(): ModelItem[] {
return this._modelManager.getGenericCompletionModels();
}
private getDefaultModelId(): string {
return this._modelManager.getDefaultModelId();
}
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ICompletionsAsyncManagerService private readonly _asyncCompletionManager: AsyncCompletionManager,
@ICompletionsModelManagerService private readonly _modelManager: AvailableModelsManager,
@ICompletionsLogTargetService private readonly _logTarget: ICompletionsLogTargetService,
@ICompletionsCacheService private readonly _completionsCache: CompletionsCache
) { }
async setUserSelectedCompletionModel(modelId: string | null) {
return workspace
.getConfiguration(CopilotConfigPrefix)
.update(ConfigKey.UserSelectedCompletionModel, modelId ?? '', true);
}
async handleModelSelection(quickpickList: QuickPick<ModelPickerItem>) {
const model = quickpickList.activeItems[0];
if (model === undefined) {
return;
}
quickpickList.hide();
// Open up the link
if (model.type === 'learn-more') {
await env.openExternal(Uri.parse(this.MODELS_INFO_URL));
this._instantiationService.invokeFunction(telemetry, 'modelPicker.learnMoreClicked');
return;
}
await this.selectModel(model);
}
async selectModel(model: ModelPickerItem) {
const currentModel = this._instantiationService.invokeFunction(getUserSelectedModelConfiguration);
if (currentModel !== model.modelId) {
this._completionsCache.clear();
this._asyncCompletionManager.clear();
}
const modelSelection = model.modelId === this.getDefaultModelId() ? null : model.modelId;
await this.setUserSelectedCompletionModel(modelSelection);
if (modelSelection === null) {
logger.info(this._logTarget, `User selected default model; setting null`);
} else {
logger.info(this._logTarget, `Selected model: ${model.modelId}`);
}
this._instantiationService.invokeFunction(
telemetry,
'modelPicker.modelSelected',
TelemetryData.createAndMarkAsIssued({
engineName: modelSelection ?? 'default',
})
);
}
private modelsForModelPicker(): [string | null, ModelPickerItem[]] {
const currentModelSelection = this._instantiationService.invokeFunction(getUserSelectedModelConfiguration);
const items: ModelPickerItem[] = this.models.map(model => {
return {
modelId: model.modelId,
label: `${model.label}${model.preview ? ' (Preview)' : ''}`,
description: `(${model.modelId})`,
alwaysShow: model.modelId === this.getDefaultModelId(),
type: 'model' as const,
};
});
return [currentModelSelection, items];
}
showModelPicker(): QuickPick<ModelPickerItem> {
const [currentModelSelection, items] = this.modelsForModelPicker();
const quickPick = window.createQuickPick<ModelPickerItem>();
quickPick.title = 'Change Completions Model';
quickPick.items = [...items, ...defaultModelPickerItems];
quickPick.onDidAccept(() => this.handleModelSelection(quickPick));
const currentModelOrDefault = currentModelSelection ?? this.getDefaultModelId();
// set the currently selected model as active
const selectedItem = quickPick.items.find(item => item.modelId === currentModelOrDefault);
if (selectedItem) {
quickPick.activeItems = [selectedItem];
}
quickPick.show();
return quickPick;
}
}
function getUserSelectedModelConfiguration(accessor: ServicesAccessor): string | null {
const value = getConfig<string | null>(accessor, ConfigKey.UserSelectedCompletionModel);
return typeof value === 'string' && value.length > 0 ? value : null;
}
@@ -1,110 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Position, Range } from 'vscode';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { postInsertionTasks } from '../../../lib/src/postInsertion';
import { countLines } from '../../../lib/src/suggestions/partialSuggestions';
import { IPosition, ITextDocument } from '../../../lib/src/textDocument';
import { normalizeCompletionText, solutionCountTarget, SolutionManager } from '../lib/panelShared/common';
import { UnformattedSolution } from '../lib/panelShared/panelTypes';
import { BasePanelCompletion, ISuggestionsPanel } from './basePanelTypes';
// BaseListDocument to be shared with both the copilot and comparison completion panels.
export abstract class BaseListDocument<TPanelCompletion extends BasePanelCompletion> extends SolutionManager {
private _solutionCount = 0;
protected readonly _solutions: TPanelCompletion[] = [];
constructor(
textDocument: ITextDocument,
position: IPosition,
readonly panel: ISuggestionsPanel,
countTarget = solutionCountTarget,
@IInstantiationService protected readonly instantiationService: IInstantiationService
) {
super(textDocument, position, panel.cancellationToken, countTarget);
}
protected abstract createPanelCompletion(
unformatted: UnformattedSolution,
baseCompletion: BasePanelCompletion
): TPanelCompletion;
protected abstract shouldAddSolution(newItem: TPanelCompletion): boolean;
protected abstract runSolutionsImpl(): Promise<void>;
// Find if two solutions are duplicates by comparing their normalized text content.
protected areSolutionsDuplicates(solutionA: TPanelCompletion, solutionB: TPanelCompletion): boolean {
const stripA = normalizeCompletionText(solutionA.insertText);
const stripB = normalizeCompletionText(solutionB.insertText);
return stripA === stripB;
}
protected findDuplicateSolution(newItem: TPanelCompletion): TPanelCompletion | undefined {
return this._solutions.find(item => this.areSolutionsDuplicates(item, newItem));
}
onSolution(unformatted: UnformattedSolution) {
const offset = this.textDocument.offsetAt(this.targetPosition);
const rank = this._solutions.length;
const postInsertionCallback = () => {
const telemetryData = this.savedTelemetryData!.extendedBy(
{
choiceIndex: unformatted.choiceIndex.toString(),
engineName: unformatted.modelId || '',
},
{
compCharLen: unformatted.insertText.length,
meanProb: unformatted.meanProb,
rank,
}
);
return this.instantiationService.invokeFunction(postInsertionTasks,
'solution',
unformatted.insertText,
offset,
this.textDocument.uri,
telemetryData,
{
compType: 'full',
acceptedLength: unformatted.insertText.length,
acceptedLines: countLines(unformatted.insertText),
},
unformatted.copilotAnnotations
);
};
const baseCompletion: BasePanelCompletion = {
insertText: unformatted.insertText,
range: new Range(
new Position(unformatted.range.start.line, unformatted.range.start.character),
new Position(unformatted.range.end.line, unformatted.range.end.character)
),
copilotAnnotations: unformatted.copilotAnnotations,
postInsertionCallback,
};
const newItem = this.createPanelCompletion(unformatted, baseCompletion);
if (this.shouldAddSolution(newItem)) {
this.panel.onItem(newItem);
this._solutions.push(newItem);
}
this._solutionCount++;
this.panel.onWorkDone({ percentage: (100 * this._solutionCount) / this.solutionCountTarget });
}
onFinishedNormally() {
return this.panel.onFinished();
}
onFinishedWithError(_: string) {
return this.onFinishedNormally();
}
runQuery() {
return this.runSolutionsImpl();
}
}
@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken, Range } from 'vscode';
import { CopilotNamedAnnotationList } from '../../../../../../platform/completions-core/common/openai/copilotAnnotations';
// Base interface for a completion displayed in the panel.
export interface BasePanelCompletion {
insertText: string;
range: Range;
copilotAnnotations?: CopilotNamedAnnotationList;
postInsertionCallback: () => PromiseLike<void> | void;
}
// Interface for the suggestions panel, which handles work done notifications and item selections.
export interface ISuggestionsPanel {
cancellationToken: CancellationToken;
onWorkDone(_: { percentage: number }): void;
onItem(_: BasePanelCompletion): void;
onFinished(): void;
}
// Configuration for webview panels for completions.
export interface PanelConfig {
panelTitle: string;
webviewId: string;
webviewScriptName: string;
contextVariable: string;
commands: {
accept: string;
navigatePrevious: string;
navigateNext: string;
};
renderingMode: 'streaming' | 'batch';
shuffleSolutions: boolean;
}
// Configuration for webview panels, used to pass settings to the webview.
export interface WebviewConfig {
renderingMode: 'batch' | 'streaming';
shuffleSolutions: boolean;
}
@@ -1,338 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
CancellationTokenSource,
Disposable,
Event,
EventEmitter,
TextDocument,
Uri,
WebviewPanel,
WorkspaceEdit,
commands,
workspace,
} from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../platform/extContext/common/extensionContext';
import { debounce } from '../../../../../../util/common/debounce';
import { BasePanelCompletion, ISuggestionsPanel, PanelConfig } from './basePanelTypes';
import { Highlighter } from './highlighter';
import { getNonce, pluralize } from './utils';
//import { IPCitationDetail } from '#lib/citationManager';
interface IPCitationDetail {
license: string;
url: string;
}
export interface SuggestionsPanelManagerInterface {
activeWebviewPanel: BaseSuggestionsPanel<BasePanelCompletion> | undefined;
decrementPanelCount(): void;
}
export interface SolutionContent {
htmlSnippet: string;
citation?: { message: string; url: string };
[key: string]: unknown; // Allow additional properties for panel-specific content
}
export interface BaseWebviewMessage {
command: string;
}
interface AcceptSolutionMessage extends BaseWebviewMessage {
command: 'acceptSolution';
solutionIndex: number;
}
interface FocusSolutionMessage extends BaseWebviewMessage {
command: 'focusSolution';
solutionIndex: number;
}
interface SubmitFeedbackMessage extends BaseWebviewMessage {
command: 'submitFeedback';
solutionIndex: number;
feedback: string;
}
interface RefreshMessage extends BaseWebviewMessage {
command: 'refresh';
}
interface WebviewReadyMessage extends BaseWebviewMessage {
command: 'webviewReady';
}
export type WebviewMessage =
| AcceptSolutionMessage
| FocusSolutionMessage
| SubmitFeedbackMessage
| RefreshMessage
| WebviewReadyMessage;
export abstract class BaseSuggestionsPanel<TPanelCompletion extends BasePanelCompletion> implements ISuggestionsPanel {
private _disposables: Disposable[] = [];
#items: TPanelCompletion[] = [];
#batchItems: TPanelCompletion[] = [];
#percentage = 0;
#highlighter: Thenable<Highlighter>;
private _focusedSolution: TPanelCompletion | undefined;
private _isDisposed: boolean = false;
#documentUri: Uri;
#cts = new CancellationTokenSource();
private _onDidDispose = new EventEmitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
get cancellationToken() {
return this.#cts.token;
}
constructor(
readonly webviewPanel: WebviewPanel,
document: TextDocument,
protected suggestionsPanelManager: SuggestionsPanelManagerInterface,
protected readonly config: PanelConfig,
@IVSCodeExtensionContext protected readonly contextService: IVSCodeExtensionContext,
) {
webviewPanel.onDidDispose(() => this._dispose(), null, this._disposables);
webviewPanel.webview.html = this._getWebviewContent();
this.#documentUri = document.uri;
this.#highlighter = Highlighter.create(document.languageId);
workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('workbench.colorTheme')) {
return this.render();
}
});
webviewPanel.webview.onDidReceiveMessage(async (message: WebviewMessage) => {
// First lest the subclass handle custom messages
if ((await this.handleCustomMessage(message)) === true) {
return;
}
switch (message.command) {
case 'focusSolution':
this._focusedSolution = this.#items[message.solutionIndex];
return;
case 'webviewReady':
// Send the config to the webview
void this.postMessage({
command: 'updateConfig',
config: {
renderingMode: this.config.renderingMode,
shuffleSolutions: this.config.shuffleSolutions,
},
});
return;
}
}, undefined);
webviewPanel.onDidChangeViewState(e => {
if (e.webviewPanel?.visible) {
this.suggestionsPanelManager.activeWebviewPanel = this;
}
});
}
protected async handleCustomMessage(message: BaseWebviewMessage): Promise<boolean> {
return Promise.resolve(false);
}
protected abstract renderSolutionContent(item: TPanelCompletion, baseContent: SolutionContent): SolutionContent;
private _buildExtensionUri(...path: string[]): Uri {
const extensionPath = Uri.joinPath(this.contextService.extensionUri, ...path);
return this.webviewPanel.webview.asWebviewUri(extensionPath);
}
private _getWebviewContent() {
const nonce = getNonce();
const scriptUri = this._buildExtensionUri('dist', this.config.webviewScriptName);
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none'; font-src ${this.webviewPanel.webview.cspSource}; style-src 'unsafe-inline' ${this.webviewPanel.webview.cspSource}; script-src 'nonce-${nonce}';"
/>
<title>${this.config.panelTitle}</title>
<style>
.solutionHeading {
margin-top: 40px;
}
pre:focus-visible {
border: 1px solid var(--vscode-focusBorder);
outline: none;
}
pre {
margin-bottom: 6px;
display: block;
padding: 9.5px;
line-height: 1.42857143;
word-break: break-all;
word-wrap: break-word;
border: 1px solid #ccc;
border-radius: 4px;
border: 1px solid var(--vscode-notebook-cellBorderColor);
white-space: pre-wrap;
font-size: var(--vscode-editor-font-size);
}
pre.shiki {
padding: 0.5em 0.7em;
margin-top: 1em;
margin-bottom: 1em;
border-radius: 4px;
}
code {
background-color: transparent;
}
</style>
</head>
<body>
<h2>${this.config.panelTitle}</h2>
<div id="loadingContainer" aria-live="assertive" aria-atomic="true">
<label for="progress-bar">Loading suggestions:</label>
<progress id="progress-bar" max="100" value="0"></progress>
</div>
<div id="solutionsContainer" aria-busy="true" aria-describedby="progress-bar"></div>
<script nonce="${nonce}" type="module" src="${scriptUri.toString()}"></script>
</body>
</html>
`;
}
onWorkDone({ percentage }: { percentage: number }) {
this.#percentage = percentage;
void this.render();
}
onItem(item: TPanelCompletion) {
// If rendering mode is 'batch', we collect items and render them later
// Otherwise, we render immediately
if (this.config.renderingMode === 'batch') {
this.#batchItems.push(item);
} else {
this.#items.push(item);
void this.render();
}
}
clearSolutions() {
// Cancel any ongoing operations
this.#cts.cancel();
// Create a new cancellation token source for the next operation
this.#cts = new CancellationTokenSource();
// Clear all solutions and reset state
this.#items = [];
this.#batchItems = [];
this._focusedSolution = undefined;
this.#percentage = 0;
void this.render();
}
onFinished() {
this.#percentage = 100;
// If we have batch items, add them to the main items list, shuffle if needed, and render
if (this.#batchItems.length > 0) {
this.#items.push(...this.#batchItems);
if (this.config.shuffleSolutions) {
this.#items = this.#items.sort(() => Math.random() - 0.5);
}
this.#batchItems = [];
}
void this.render();
}
protected async acceptSolution(solution: TPanelCompletion, closePanel: boolean = true) {
if (this._isDisposed === false && solution?.range) {
const edit = new WorkspaceEdit();
edit.replace(this.#documentUri, solution.range, solution.insertText);
await workspace.applyEdit(edit);
this.#cts.cancel();
if (closePanel) {
await commands.executeCommand('workbench.action.closeActiveEditor');
}
await solution.postInsertionCallback();
}
}
protected items(): TPanelCompletion[] {
return this.#items;
}
async acceptFocusedSolution() {
const solution = this._focusedSolution;
if (solution) {
return this.acceptSolution(solution);
}
}
protected async renderSolutions() {
const highlighter = await this.#highlighter;
const content = this.#items.map(item => {
const firstCitation = item.copilotAnnotations?.ip_code_citations?.[0];
const details = firstCitation?.details.citations as IPCitationDetail[] | undefined;
let renderedCitatation: { message: string; url: string } | undefined;
if (details && details.length > 0) {
const licensesSet = new Set(details.map(d => d.license));
if (licensesSet.has('NOASSERTION')) {
licensesSet.delete('NOASSERTION');
licensesSet.add('unknown');
}
const allLicenses = Array.from(licensesSet).sort();
const licenseString = allLicenses.length === 1 ? allLicenses[0] : `[${allLicenses.join(', ')}]`;
renderedCitatation = {
message: `Similar code with ${pluralize(allLicenses.length, 'license type')} ${licenseString} detected.`,
url: details[0].url,
};
}
const baseContent = {
htmlSnippet: highlighter.createSnippet(item.insertText.trim()),
citation: renderedCitatation,
};
return this.renderSolutionContent(item, baseContent);
});
const message = this.createSolutionsMessage(content, this.#percentage);
await this.postMessage(message);
}
// Subclasses must implement this to create their specific message format
protected abstract createSolutionsMessage(content: SolutionContent[], percentage: number): unknown;
render = debounce(10, () => this.renderSolutions());
postMessage(message: unknown) {
if (this._isDisposed === false) {
return this.webviewPanel.webview.postMessage(message);
}
}
private _dispose() {
this._isDisposed = true;
this._onDidDispose.fire();
this.suggestionsPanelManager.decrementPanelCount();
while (this._disposables.length) {
const disposable = this._disposables.pop();
if (disposable) {
disposable.dispose();
}
}
this._onDidDispose.dispose();
}
}
@@ -1,98 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TextDocument, Uri, ViewColumn, WebviewPanel, commands, window } from 'vscode';
import { IVSCodeExtensionContext } from '../../../../../../platform/extContext/common/extensionContext';
import { DisposableStore, IDisposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { IPosition, ITextDocument } from '../../../lib/src/textDocument';
import { basename } from '../../../lib/src/util/uri';
import { registerCommandWrapper } from '../telemetry';
import { BasePanelCompletion, PanelConfig } from './basePanelTypes';
import { BaseSuggestionsPanel, SuggestionsPanelManagerInterface } from './baseSuggestionsPanel';
export interface ListDocumentInterface {
runQuery(): Promise<void>;
}
export abstract class BaseSuggestionsPanelManager<TPanelCompletion extends BasePanelCompletion>
implements SuggestionsPanelManagerInterface {
activeWebviewPanel: BaseSuggestionsPanel<TPanelCompletion> | undefined;
private _panelCount: number = 0;
constructor(
protected readonly config: PanelConfig,
@IInstantiationService protected readonly _instantiationService: IInstantiationService,
@IVSCodeExtensionContext protected readonly _extensionContext: IVSCodeExtensionContext,
) { }
protected abstract createListDocument(
wrapped: ITextDocument,
position: IPosition,
panel: BaseSuggestionsPanel<TPanelCompletion>
): ListDocumentInterface;
protected abstract createSuggestionsPanel(
panel: WebviewPanel,
document: TextDocument,
manager: this
): BaseSuggestionsPanel<TPanelCompletion>;
renderPanel(
document: TextDocument,
position: IPosition,
wrapped: ITextDocument
): BaseSuggestionsPanel<TPanelCompletion> {
const title = `${this.config.panelTitle} for ${basename(document.uri.toString()) || document.uri.toString()}`;
const panel = window.createWebviewPanel(this.config.webviewId, title, ViewColumn.Two, {
enableScripts: true,
localResourceRoots: [Uri.joinPath(this._extensionContext.extensionUri, 'dist')],
retainContextWhenHidden: true,
});
const suggestionPanel = this.createSuggestionsPanel(panel, document, this);
// Listen for the panel disposal event to clear our reference
suggestionPanel.onDidDispose(() => {
if (this.activeWebviewPanel === suggestionPanel) {
this.activeWebviewPanel = undefined;
}
});
void this.createListDocument(wrapped, position, suggestionPanel).runQuery();
this.activeWebviewPanel = suggestionPanel;
this._panelCount = this._panelCount + 1;
return suggestionPanel;
}
registerCommands(): IDisposable {
const disposableStore = new DisposableStore();
disposableStore.add(this._instantiationService.invokeFunction(registerCommandWrapper, this.config.commands.accept, () => {
return this.activeWebviewPanel?.acceptFocusedSolution();
}));
disposableStore.add(this._instantiationService.invokeFunction(registerCommandWrapper, this.config.commands.navigatePrevious, () => {
return this.activeWebviewPanel?.postMessage({
command: 'navigatePreviousSolution',
});
}));
disposableStore.add(this._instantiationService.invokeFunction(registerCommandWrapper, this.config.commands.navigateNext, () => {
return this.activeWebviewPanel?.postMessage({
command: 'navigateNextSolution',
});
}));
return disposableStore;
}
decrementPanelCount() {
this._panelCount = this._panelCount - 1;
if (this._panelCount === 0) {
void commands.executeCommand('setContext', this.config.contextVariable, false);
}
}
}
@@ -1,117 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getSingletonHighlighterCore, HighlighterCore, ThemeRegistration, ThemeRegistrationAny } from 'shiki/core';
import * as langs from 'shiki/langs';
import { BundledLanguage } from 'shiki/langs';
import getWasmInlined from 'shiki/wasm';
import { ColorThemeKind, window, workspace } from 'vscode';
import * as languages from './languages';
import * as themes from './themes';
export class Highlighter {
private constructor(
private languageId: string | undefined,
private highlighter: HighlighterCore | undefined
) { }
static async create(languageId = window.activeTextEditor?.document.languageId): Promise<Highlighter> {
if (!languageId) {
return new Highlighter(undefined, undefined);
}
const highlighter = await getSingletonHighlighterCore({
langs: Object.values(langs.bundledLanguages),
loadWasm: getWasmInlined,
});
// Load additional language if not out of the box for shiki
if (!langs.bundledLanguages[languageId as BundledLanguage]) {
const additionalLang = vscLanguageMap[languageId as keyof typeof vscLanguageMap];
if (additionalLang) {
await highlighter.loadLanguage(additionalLang);
}
}
return new Highlighter(languageId, highlighter);
}
createSnippet(text: string): string {
if (!this.highlighter || !this.languageId || !this.languageSupported()) {
return `<pre>${text}</pre>`;
}
return this.highlighter.codeToHtml(text, { lang: this.languageId, theme: getCurrentTheme() });
}
private languageSupported() {
if (!this.languageId) { return false; }
if (this.highlighter?.getLoadedLanguages().includes(this.languageId)) {
return true;
}
return false;
}
}
function getCurrentTheme(): ThemeRegistration {
const workbenchConfig = workspace.getConfiguration('workbench');
if (workbenchConfig) {
const vsCodeTheme = workbenchConfig.get<string>('colorTheme');
if (vsCodeTheme && isSupportedTheme(vsCodeTheme)) {
return vscThemeMap[vsCodeTheme];
}
const themeType = window.activeColorTheme;
const defaultTheme = vscDefaultMap[themeType.kind]; // fall back to default themes if we don't have a match
return defaultTheme;
} else {
return vscThemeMap['Default Dark Modern'];
}
}
const vscDefaultMap: { [key in ColorThemeKind]: ThemeRegistrationAny } = {
[ColorThemeKind.Dark]: themes.darkModern,
[ColorThemeKind.Light]: themes.lightModern,
[ColorThemeKind.HighContrast]: themes.darkHC,
[ColorThemeKind.HighContrastLight]: themes.lightHC,
};
// These are vs code themes that aren't out of the box in shiki but come standard with vs code
const vscThemeMap: { [key: string]: ThemeRegistrationAny } = {
Abyss: themes.abyss,
'Dark High Contrast': themes.darkHC,
'Light High Constrast': themes.lightHC,
'Default Dark Modern': themes.darkModern,
'Kimbie Dark': themes.kimbieDark,
'Default Light Modern': themes.lightModern,
'Monokai Dimmed': themes.monokaiDim,
'Quiet Light': themes.quietLight,
Red: themes.red,
'Tomorrow Night Blue': themes.tomorrowNightBlue,
'Visual Studio Dark': themes.vsDark,
'Visual Studio Light': themes.vsLight,
'Default Dark+': themes.darkPlus,
'Default Light+': themes.lightPlus,
Monokai: themes.monokai,
'Solarized Dark': themes.solarizedDark,
'Solarized Light': themes.solarizedLight,
} as const;
function isSupportedTheme(theme: keyof typeof vscThemeMap): theme is keyof typeof vscThemeMap {
return theme in vscThemeMap;
}
// These are vs code themes that aren't out of the box in shiki but come standard with vs code
const vscLanguageMap = {
'cuda-cpp': languages.cudaCpp,
javascriptreact: languages.javascriptreact,
markdown_latex_combined: languages.markdownLatexCombined,
'markdown-math': languages.markdownMath,
restructuredtext: languages.restructuredtext,
'search-result': languages.searchResult,
typescriptreact: languages.typescriptreact,
} as const;
File diff suppressed because one or more lines are too long
@@ -1,11 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export { cudaCpp } from './cuda-cpp.tmLanguage';
export { javascriptreact } from './javaScriptReact.tmLanguage';
export { markdownLatexCombined } from './markdown-latex-combined.tmLanguage';
export { markdownMath } from './md-math.tmLanguage';
export { restructuredtext } from './rst.tmLanguage';
export { searchResult } from './searchResult.tmLanguage';
export { typescriptreact } from './typeScriptReact.tmLanguage';
File diff suppressed because one or more lines are too long
@@ -1,113 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { LanguageInput } from 'shiki/core';
// This file includes some grammar rules copied from https://github.com/James-Yu/LaTeX-Workshop/blob/master/syntax/TeX.tmLanguage.json',
export const markdownMath: LanguageInput = {
name: 'markdown-math',
scopeName: 'text.html.markdown.math',
patterns: [
{
include: '#math',
},
],
repository: {
$self: {},
$base: {},
math: {
patterns: [
{
name: 'comment.line.math.tex',
match: '((?<!\\\\)%)(.+)$',
captures: {
'1': {
name: 'punctuation.definition.comment.math.tex',
},
},
},
{
name: 'line.separator.math.tex',
match: '(\\\\\\\\)$',
captures: {
'1': {
name: 'punctuation.line.separator.math.tex',
},
},
},
{
name: 'meta.function.math.tex',
begin: '((\\\\)([a-zA-Z_]+))\\s*(\\{)',
beginCaptures: {
'1': {
name: 'storage.type.function.math.tex',
},
'2': {
name: 'punctuation.definition.function.math.tex',
},
'3': {
name: 'entity.name.function.math.tex',
},
'4': {
name: 'punctuation.definition.arguments.begin.math.tex',
},
},
end: '\\}',
endCaptures: {
'0': {
name: 'punctuation.definition.arguments.end.math.tex',
},
},
patterns: [
{
include: '$self',
},
],
},
{
captures: {
'1': {
name: 'punctuation.definition.constant.math.tex',
},
},
match: '(\\\\)([a-zA-Z_]+)\\b',
name: 'constant.character.math.tex',
},
{
captures: {
'1': {
name: 'punctuation.definition.constant.math.tex',
},
},
match: '(\\\\)(?!begin\\*\\{|verb)([A-Za-z]+)',
name: 'constant.other.general.math.tex',
},
{
match: '(?<!\\\\)\\{',
name: 'punctuation.math.begin.bracket.curly',
},
{
match: '(?<!\\\\)\\}',
name: 'punctuation.math.end.bracket.curly',
},
{
match: '\\(',
name: 'punctuation.math.begin.bracket.round',
},
{
match: '\\)',
name: 'punctuation.math.end.bracket.round',
},
{
match: '(([0-9]*[\\.][0-9]+)|[0-9]+)',
name: 'constant.numeric.math.tex',
},
{
match: '[\\+\\*/_\\^-]',
name: 'punctuation.math.operator.latex',
},
],
},
},
};
@@ -1,740 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* eslint-disable local/no-unexternalized-strings */
import { LanguageInput } from 'shiki/core';
// This file has been converted from https://github.com/trond-snekvik/vscode-rst/blob/master/syntaxes/rst.tmLanguage.json
// If you want to provide a fix or improvement, please create a pull request against the original repository.
// Once accepted there, we are happy to receive an update request.
// version: https://github.com/trond-snekvik/vscode-rst/commit/f0fe19ffde6509be52ad9267a57e1b3df665f072
export const restructuredtext: LanguageInput = {
scopeName: 'source.rst',
name: 'restructuredtext',
patterns: [
{
include: '#body',
},
],
repository: {
$self: {},
$base: {},
body: {
patterns: [
{
include: '#title',
},
{
include: '#inline-markup',
},
{
include: '#anchor',
},
{
include: '#line-block',
},
{
include: '#replace-include',
},
{
include: '#footnote',
},
{
include: '#substitution',
},
{
include: '#blocks',
},
{
include: '#table',
},
{
include: '#simple-table',
},
{
include: '#options-list',
},
],
},
title: {
match: '^(\\*{3,}|#{3,}|\\={3,}|~{3,}|\\+{3,}|-{3,}|`{3,}|\\^{3,}|:{3,}|"{3,}|_{3,}|\'{3,})$',
name: 'markup.heading',
},
'inline-markup': {
patterns: [
{
include: '#escaped',
},
{
include: '#ignore',
},
{
include: '#ref',
},
{
include: '#literal',
},
{
include: '#monospaced',
},
{
include: '#citation',
},
{
include: '#bold',
},
{
include: '#italic',
},
{
include: '#list',
},
{
include: '#macro',
},
{
include: '#reference',
},
{
include: '#footnote-ref',
},
],
},
ignore: {
patterns: [
{
match: "'[`*]+'",
},
{
match: '<[`*]+>',
},
{
match: '{[`*]+}',
},
{
match: '\\([`*]+\\)',
},
{
match: '\\[[`*]+\\]',
},
{
match: '"[`*]+"',
},
],
},
table: {
begin: '^\\s*\\+[=+-]+\\+\\s*$',
end: '^(?![+|])',
beginCaptures: {
'0': {
name: 'keyword.control.table',
},
},
patterns: [
{
match: '[=+|-]',
name: 'keyword.control.table',
},
],
},
'simple-table': {
match: '^[=\\s]+$',
name: 'keyword.control.table',
},
ref: {
begin: '(:ref:)`',
end: '`|^\\s*$',
name: 'entity.name.tag',
beginCaptures: {
'1': {
name: 'keyword.control',
},
},
patterns: [
{
match: '<.*?>',
name: 'markup.underline.link',
},
],
},
reference: {
match: '[\\w-]*[a-zA-Z\\d-]__?\\b',
name: 'entity.name.tag',
},
macro: {
match: '\\|[^\\|]+\\|',
name: 'entity.name.tag',
},
literal: {
match: '(:\\S+:)(`.*?`\\\\?)',
captures: {
'1': {
name: 'keyword.control',
},
'2': {
name: 'entity.name.tag',
},
},
},
monospaced: {
begin: '(?<=[\\s"\'(\\[{<]|^)``[^\\s`]',
end: '``|^\\s*$',
name: 'string.interpolated',
},
citation: {
begin: '(?<=[\\s"\'(\\[{<]|^)`[^\\s`]',
end: '`_{,2}|^\\s*$',
name: 'entity.name.tag',
applyEndPatternLast: false,
},
bold: {
begin: '(?<=[\\s"\'(\\[{<]|^)\\*{2}[^\\s*]',
end: '\\*{2}|^\\s*$',
name: 'markup.bold',
},
italic: {
begin: '(?<=[\\s"\'(\\[{<]|^)\\*[^\\s*]',
end: '\\*|^\\s*$',
name: 'markup.italic',
},
escaped: {
match: '\\\\.',
name: 'constant.character.escape',
},
list: {
match: '^\\s*(\\d+\\.|\\* -|[a-zA-Z#]\\.|[iIvVxXmMcC]+\\.|\\(\\d+\\)|\\d+\\)|[*+-])\\s+',
name: 'keyword.control',
},
'line-block': {
match: '^\\|\\s+',
name: 'keyword.control',
},
'raw-html': {
begin: '^(\\s*)(\\.{2}\\s+raw\\s*::)\\s+(html)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'3': {
name: 'variable.parameter.html',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'text.html.derivative',
},
],
},
anchor: {
match: '^\\.{2}\\s+(_[^:]+:)\\s*',
name: 'entity.name.tag.anchor',
},
'replace-include': {
match: '^\\s*(\\.{2})\\s+(\\|[^\\|]+\\|)\\s+(replace::)',
captures: {
'1': {
name: 'keyword.control',
},
'2': {
name: 'entity.name.tag',
},
'3': {
name: 'keyword.control',
},
},
},
footnote: {
match: '^\\s*\\.{2}\\s+\\[(?:[\\w\\.-]+|[#*]|#\\w+)\\]\\s+',
name: 'entity.name.tag',
},
'footnote-ref': {
match: '\\[(?:[\\w\\.-]+|[#*])\\]_',
name: 'entity.name.tag',
},
substitution: {
match: '^\\.{2}\\s*\\|([^|]+)\\|',
name: 'entity.name.tag',
},
'options-list': {
match: '^((?:-\\w|--[\\w-]+|/\\w+)(?:,? ?[\\w-]+)*)(?: |\\t|$)',
name: 'variable.parameter',
},
blocks: {
patterns: [
{
include: '#domains',
},
{
include: '#doctest',
},
{
include: '#code-block-cpp',
},
{
include: '#code-block-py',
},
{
include: '#code-block-console',
},
{
include: '#code-block-javascript',
},
{
include: '#code-block-yaml',
},
{
include: '#code-block-cmake',
},
{
include: '#code-block-kconfig',
},
{
include: '#code-block-ruby',
},
{
include: '#code-block-dts',
},
{
include: '#code-block',
},
{
include: '#doctest-block',
},
{
include: '#raw-html',
},
{
include: '#block',
},
{
include: '#literal-block',
},
{
include: '#block-comment',
},
],
},
'block-comment': {
begin: '^(\\s*)\\.{2}',
while: '^\\1(?=\\s)|^\\s*$',
name: 'comment.block',
},
'literal-block': {
begin: '^(\\s*)(.*)(::)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
patterns: [
{
include: '#inline-markup',
},
],
},
'3': {
name: 'keyword.control',
},
},
},
block: {
begin: '^(\\s*)(\\.{2}\\s+\\S+::)(.*)',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'3': {
name: 'variable',
},
},
patterns: [
{
include: '#block-param',
},
{
include: '#body',
},
],
},
'block-param': {
patterns: [
{
match: '(:param\\s+(.+?):)(?:\\s|$)',
captures: {
'1': {
name: 'keyword.control',
},
'2': {
name: 'variable.parameter',
},
},
},
{
match: '(:.+?:)(?:$|\\s+(.*))',
captures: {
'1': {
name: 'keyword.control',
},
'2': {
patterns: [
{
match: '\\b(0x[a-fA-F\\d]+|\\d+)\\b',
name: 'constant.numeric',
},
{
include: '#inline-markup',
},
],
},
},
},
],
},
domains: {
patterns: [
{
include: '#domain-cpp',
},
{
include: '#domain-py',
},
{
include: '#domain-auto',
},
{
include: '#domain-js',
},
],
},
'domain-cpp': {
begin: '^(\\s*)(\\.{2}\\s+(?:cpp|c):(?:class|struct|function|member|var|type|enum|enum-struct|enum-class|enumerator|union|concept)::)\\s*(?:(@\\w+)|(.*))',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'3': {
name: 'entity.name.tag',
},
'4': {
patterns: [
{
include: 'source.cpp',
},
],
},
},
patterns: [
{
include: '#block-param',
},
{
include: '#body',
},
],
},
'domain-py': {
begin: '^(\\s*)(\\.{2}\\s+py:(?:module|function|data|exception|class|attribute|property|method|staticmethod|classmethod|decorator|decoratormethod)::)\\s*(.*)',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'3': {
patterns: [
{
include: 'source.python',
},
],
},
},
patterns: [
{
include: '#block-param',
},
{
include: '#body',
},
],
},
'domain-auto': {
begin: '^(\\s*)(\\.{2}\\s+auto(?:class|module|exception|function|decorator|data|method|attribute|property)::)\\s*(.*)',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control.py',
},
'3': {
patterns: [
{
include: 'source.python',
},
],
},
},
patterns: [
{
include: '#block-param',
},
{
include: '#body',
},
],
},
'domain-js': {
begin: '^(\\s*)(\\.{2}\\s+js:\\w+::)\\s*(.*)',
end: '^(?!\\1[ \\t]|$)',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'3': {
patterns: [
{
include: 'source.js',
},
],
},
},
patterns: [
{
include: '#block-param',
},
{
include: '#body',
},
],
},
doctest: {
begin: '^(>>>)\\s*(.*)',
end: '^\\s*$',
beginCaptures: {
'1': {
name: 'keyword.control',
},
'2': {
patterns: [
{
include: 'source.python',
},
],
},
},
},
'code-block-cpp': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(c|c\\+\\+|cpp|C|C\\+\\+|CPP|Cpp)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.cpp',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.cpp',
},
],
},
'code-block-console': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(console|shell|bash)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.console',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.shell',
},
],
},
'code-block-py': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(python)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.py',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.python',
},
],
},
'code-block-javascript': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(javascript)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.js',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.js',
},
],
},
'code-block-yaml': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(ya?ml)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.yaml',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.yaml',
},
],
},
'code-block-cmake': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(cmake)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.cmake',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.cmake',
},
],
},
'code-block-kconfig': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*([kK]config)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.kconfig',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.kconfig',
},
],
},
'code-block-ruby': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(ruby)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.ruby',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.ruby',
},
],
},
'code-block-dts': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)\\s*(dts|DTS|devicetree)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
'4': {
name: 'variable.parameter.codeblock.dts',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.dts',
},
],
},
'code-block': {
begin: '^(\\s*)(\\.{2}\\s+(code|code-block)::)',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
},
patterns: [
{
include: '#block-param',
},
],
},
'doctest-block': {
begin: '^(\\s*)(\\.{2}\\s+doctest::)\\s*$',
while: '^\\1(?=\\s)|^\\s*$',
beginCaptures: {
'2': {
name: 'keyword.control',
},
},
patterns: [
{
include: '#block-param',
},
{
include: 'source.python',
},
],
},
},
};
File diff suppressed because one or more lines are too long
@@ -1,343 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const abyss: ThemeRegistrationAny = {
type: 'dark',
colors: {
'activityBar.background': '#051336',
'badge.background': '#0063a5',
'button.background': '#2b3c5d',
'debugExceptionWidget.background': '#051336',
'debugExceptionWidget.border': '#ab395b',
'debugToolBar.background': '#051336',
'diffEditor.insertedTextBackground': '#31958a55',
'diffEditor.removedTextBackground': '#892f4688',
'dropdown.background': '#181f2f',
'editor.background': '#000c18',
'editor.findMatchHighlightBackground': '#eeeeee44',
'editor.foreground': '#6688cc',
'editor.lineHighlightBackground': '#082050',
'editor.selectionBackground': '#770811',
'editorCursor.foreground': '#ddbb88',
'editorGroup.border': '#2b2b4a',
'editorGroup.dropBackground': '#25375daa',
'editorGroupHeader.tabsBackground': '#1c1c2a',
'editorHoverWidget.background': '#000c38',
'editorHoverWidget.border': '#004c18',
'editorIndentGuide.activeBackground': '#204972',
'editorIndentGuide.background': '#002952',
'editorLineNumber.activeForeground': '#80a2c2',
'editorLineNumber.foreground': '#406385',
'editorLink.activeForeground': '#0063a5',
'editorMarkerNavigation.background': '#060621',
'editorMarkerNavigationError.background': '#ab395b',
'editorMarkerNavigationWarning.background': '#5b7e7a',
'editorWhitespace.foreground': '#103050',
'editorWidget.background': '#262641',
'extensionButton.prominentBackground': '#5f8b3b',
'extensionButton.prominentHoverBackground': '#5f8b3bbb',
focusBorder: '#596f99',
'input.background': '#181f2f',
'inputOption.activeBorder': '#1d4a87',
'inputValidation.errorBackground': '#a22d44',
'inputValidation.errorBorder': '#ab395b',
'inputValidation.infoBackground': '#051336',
'inputValidation.infoBorder': '#384078',
'inputValidation.warningBackground': '#5b7e7a',
'inputValidation.warningBorder': '#5b7e7a',
'list.activeSelectionBackground': '#08286b',
'list.dropBackground': '#041d52',
'list.highlightForeground': '#0063a5',
'list.hoverBackground': '#061940',
'list.inactiveSelectionBackground': '#152037',
'minimap.selectionHighlight': '#750000',
'panel.border': '#2b2b4a',
'peekView.border': '#2b2b4a',
'peekViewEditor.background': '#10192c',
'peekViewEditor.matchHighlightBackground': '#eeeeee33',
'peekViewResult.background': '#060621',
'peekViewResult.matchHighlightBackground': '#eeeeee44',
'peekViewTitle.background': '#10192c',
'pickerGroup.border': '#596f99',
'pickerGroup.foreground': '#596f99',
'ports.iconRunningProcessForeground': '#80a2c2',
'progressBar.background': '#0063a5',
'quickInputList.focusBackground': '#08286b',
'scrollbar.shadow': '#515e91aa',
'scrollbarSlider.activeBackground': '#3b3f5188',
'scrollbarSlider.background': '#1f2230aa',
'scrollbarSlider.hoverBackground': '#3b3f5188',
'sideBar.background': '#060621',
'sideBarSectionHeader.background': '#10192c',
'statusBar.background': '#10192c',
'statusBar.debuggingBackground': '#10192c',
'statusBar.noFolderBackground': '#10192c',
'statusBarItem.prominentBackground': '#0063a5',
'statusBarItem.prominentHoverBackground': '#0063a5dd',
'statusBarItem.remoteBackground': '#0063a5',
'tab.border': '#2b2b4a',
'tab.inactiveBackground': '#10192c',
'tab.lastPinnedBorder': '#2b3c5d',
'terminal.ansiBlack': '#111111',
'terminal.ansiBlue': '#bbdaff',
'terminal.ansiBrightBlack': '#333333',
'terminal.ansiBrightBlue': '#80baff',
'terminal.ansiBrightCyan': '#78ffff',
'terminal.ansiBrightGreen': '#b8f171',
'terminal.ansiBrightMagenta': '#d778ff',
'terminal.ansiBrightRed': '#ff7882',
'terminal.ansiBrightWhite': '#ffffff',
'terminal.ansiBrightYellow': '#ffe580',
'terminal.ansiCyan': '#99ffff',
'terminal.ansiGreen': '#d1f1a9',
'terminal.ansiMagenta': '#ebbbff',
'terminal.ansiRed': '#ff9da4',
'terminal.ansiWhite': '#cccccc',
'terminal.ansiYellow': '#ffeead',
'titleBar.activeBackground': '#10192c',
},
tokenColors: [
{
scope: ['meta.embedded', 'source.groovy.embedded', 'string meta.image.inline.markdown'],
settings: {
foreground: '#6688CC',
},
},
{
scope: 'comment',
settings: {
foreground: '#384887',
},
},
{
scope: 'string',
settings: {
foreground: '#22AA44',
},
},
{
scope: 'constant.numeric',
settings: {
foreground: '#F280D0',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#F280D0',
},
},
{
scope: ['constant.character', 'constant.other'],
settings: {
foreground: '#F280D0',
},
},
{
scope: 'variable',
settings: {
fontStyle: '',
},
},
{
scope: 'keyword',
settings: {
foreground: '#225588',
},
},
{
scope: 'storage',
settings: {
foreground: '#225588',
fontStyle: '',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#9966B8',
fontStyle: 'italic',
},
},
{
scope: ['entity.name.class', 'entity.name.type', 'entity.name.namespace', 'entity.name.scope-resolution'],
settings: {
foreground: '#FFEEBB',
fontStyle: 'underline',
},
},
{
scope: 'entity.other.inherited-class',
settings: {
foreground: '#DDBB88',
fontStyle: 'italic underline',
},
},
{
scope: 'entity.name.function',
settings: {
foreground: '#DDBB88',
fontStyle: '',
},
},
{
scope: 'variable.parameter',
settings: {
foreground: '#2277FF',
fontStyle: 'italic',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#225588',
fontStyle: '',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#DDBB88',
fontStyle: '',
},
},
{
scope: 'support.function',
settings: {
foreground: '#9966B8',
fontStyle: '',
},
},
{
scope: 'support.constant',
settings: {
foreground: '#9966B8',
fontStyle: '',
},
},
{
scope: ['support.type', 'support.class'],
settings: {
foreground: '#9966B8',
fontStyle: 'italic',
},
},
{
scope: 'support.other.variable',
settings: {
fontStyle: '',
},
},
{
scope: 'invalid',
settings: {
foreground: '#A22D44',
fontStyle: '',
},
},
{
scope: 'invalid.deprecated',
settings: {
foreground: '#A22D44',
},
},
{
scope: ['meta.diff', 'meta.diff.header'],
settings: {
foreground: '#E0EDDD',
fontStyle: 'italic',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#DC322F',
fontStyle: '',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#CB4B16',
fontStyle: '',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#219186',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#22AA44',
},
},
{
scope: ['markup.bold', 'markup.italic'],
settings: {
foreground: '#22AA44',
},
},
{
scope: 'markup.bold',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#9966B8',
fontStyle: '',
},
},
{
scope: ['markup.heading', 'markup.heading.setext'],
settings: {
foreground: '#6688CC',
fontStyle: 'bold',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,462 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const darkHC: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'actionBar.toggledBackground': '#383a49',
'editor.background': '#000000',
'editor.foreground': '#ffffff',
'editor.selectionBackground': '#ffffff',
'editorIndentGuide.activeBackground1': '#ffffff',
'editorIndentGuide.background1': '#ffffff',
'editorWhitespace.foreground': '#7c7c7c',
'ports.iconRunningProcessForeground': '#ffffff',
'selection.background': '#008000',
'sideBarTitle.foreground': '#ffffff',
'statusBarItem.remoteBackground': '#00000000',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#000080',
},
},
{
scope: 'comment',
settings: {
foreground: '#7CA668',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#569CD6',
},
},
{
scope: [
'constant.numeric',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#B46695',
},
},
{
scope: 'constant.character',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'entity.name.tag.css',
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'invalid',
settings: {
foreground: '#F44747',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#6796E6',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#569CD6',
},
},
{
scope: ['punctuation.definition.tag'],
settings: {
foreground: '#808080',
},
},
{
scope: 'meta.preprocessor',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'storage',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage.modifier',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'string',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.tag',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.value',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#D16969',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#FFFFFF',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'keyword',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#D4D4D4',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.logical.python',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'variable.language.this',
settings: {
foreground: '#569CD6',
},
},
{
scope: [
'entity.name.function',
'support.function',
'support.constant.handlebars',
'source.powershell variable.other.member',
],
settings: {
foreground: '#DCDCAA',
},
},
{
scope: [
'support.class',
'support.type',
'entity.name.type',
'entity.name.namespace',
'entity.name.scope-resolution',
'entity.name.class',
'storage.type.cs',
'storage.type.generic.cs',
'storage.type.modifier.cs',
'storage.type.variable.cs',
'storage.type.annotation.java',
'storage.type.generic.java',
'storage.type.java',
'storage.type.object.array.java',
'storage.type.primitive.array.java',
'storage.type.primitive.java',
'storage.type.token.java',
'storage.type.groovy',
'storage.type.annotation.groovy',
'storage.type.parameters.groovy',
'storage.type.generic.groovy',
'storage.type.object.array.groovy',
'storage.type.primitive.array.groovy',
'storage.type.primitive.groovy',
],
settings: {
foreground: '#4EC9B0',
},
},
{
scope: [
'meta.type.cast.expr',
'meta.type.new.expr',
'support.constant.math',
'support.constant.dom',
'support.constant.json',
'entity.other.inherited-class',
],
settings: {
foreground: '#4EC9B0',
},
},
{
scope: [
'keyword.control',
'source.cpp keyword.operator.new',
'source.cpp keyword.operator.delete',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
],
settings: {
foreground: '#C586C0',
},
},
{
scope: ['variable', 'meta.definition.variable.name', 'support.variable'],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: ['meta.object-literal.key'],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#CE9178',
},
},
{
scope: 'meta.resultLinePrefix.contextLinePrefix.search',
settings: {
foreground: '#CBEDCB',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#008000',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#FF0000',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,692 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const darkModern: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'actionBar.toggledBackground': '#383a49',
'activityBar.activeBorder': '#0078d4',
'activityBar.background': '#181818',
'activityBar.border': '#2b2b2b',
'activityBar.foreground': '#d7d7d7',
'activityBar.inactiveForeground': '#868686',
'activityBarBadge.background': '#0078d4',
'activityBarBadge.foreground': '#ffffff',
'badge.background': '#616161',
'badge.foreground': '#f8f8f8',
'button.background': '#0078d4',
'button.border': '#ffffff12',
'button.foreground': '#ffffff',
'button.hoverBackground': '#026ec1',
'button.secondaryBackground': '#313131',
'button.secondaryForeground': '#cccccc',
'button.secondaryHoverBackground': '#3c3c3c',
'chat.slashCommandBackground': '#34414b',
'chat.slashCommandForeground': '#40a6ff',
'checkbox.background': '#313131',
'checkbox.border': '#3c3c3c',
'debugToolBar.background': '#181818',
descriptionForeground: '#9d9d9d',
'dropdown.background': '#313131',
'dropdown.border': '#3c3c3c',
'dropdown.foreground': '#cccccc',
'dropdown.listBackground': '#1f1f1f',
'editor.background': '#1f1f1f',
'editor.findMatchBackground': '#9e6a03',
'editor.foreground': '#cccccc',
'editor.inactiveSelectionBackground': '#3a3d41',
'editor.selectionHighlightBackground': '#add6ff26',
'editorGroup.border': '#ffffff17',
'editorGroupHeader.tabsBackground': '#181818',
'editorGroupHeader.tabsBorder': '#2b2b2b',
'editorGutter.addedBackground': '#2ea043',
'editorGutter.deletedBackground': '#f85149',
'editorGutter.modifiedBackground': '#0078d4',
'editorIndentGuide.activeBackground1': '#707070',
'editorIndentGuide.background1': '#404040',
'editorLineNumber.activeForeground': '#cccccc',
'editorLineNumber.foreground': '#6e7681',
'editorOverviewRuler.border': '#010409',
'editorWidget.background': '#202020',
errorForeground: '#f85149',
focusBorder: '#0078d4',
foreground: '#cccccc',
'icon.foreground': '#cccccc',
'input.background': '#313131',
'input.border': '#3c3c3c',
'input.foreground': '#cccccc',
'input.placeholderForeground': '#818181',
'inputOption.activeBackground': '#2489db82',
'inputOption.activeBorder': '#2488db',
'keybindingLabel.foreground': '#cccccc',
'list.activeSelectionIconForeground': '#ffffff',
'list.dropBackground': '#383b3d',
'menu.background': '#1f1f1f',
'menu.border': '#454545',
'menu.foreground': '#cccccc',
'menu.separatorBackground': '#454545',
'notificationCenterHeader.background': '#1f1f1f',
'notificationCenterHeader.foreground': '#cccccc',
'notifications.background': '#1f1f1f',
'notifications.border': '#2b2b2b',
'notifications.foreground': '#cccccc',
'panel.background': '#181818',
'panel.border': '#2b2b2b',
'panelInput.border': '#2b2b2b',
'panelTitle.activeBorder': '#0078d4',
'panelTitle.activeForeground': '#cccccc',
'panelTitle.inactiveForeground': '#9d9d9d',
'peekViewEditor.background': '#1f1f1f',
'peekViewEditor.matchHighlightBackground': '#bb800966',
'peekViewResult.background': '#1f1f1f',
'peekViewResult.matchHighlightBackground': '#bb800966',
'pickerGroup.border': '#3c3c3c',
'ports.iconRunningProcessForeground': '#369432',
'progressBar.background': '#0078d4',
'quickInput.background': '#222222',
'quickInput.foreground': '#cccccc',
'settings.dropdownBackground': '#313131',
'settings.dropdownBorder': '#3c3c3c',
'settings.headerForeground': '#ffffff',
'settings.modifiedItemIndicator': '#bb800966',
'sideBar.background': '#181818',
'sideBar.border': '#2b2b2b',
'sideBar.foreground': '#cccccc',
'sideBarSectionHeader.background': '#181818',
'sideBarSectionHeader.border': '#2b2b2b',
'sideBarSectionHeader.foreground': '#cccccc',
'sideBarTitle.foreground': '#cccccc',
'statusBar.background': '#181818',
'statusBar.border': '#2b2b2b',
'statusBar.debuggingBackground': '#0078d4',
'statusBar.debuggingForeground': '#ffffff',
'statusBar.focusBorder': '#0078d4',
'statusBar.foreground': '#cccccc',
'statusBar.noFolderBackground': '#1f1f1f',
'statusBarItem.focusBorder': '#0078d4',
'statusBarItem.prominentBackground': '#6e768166',
'statusBarItem.remoteBackground': '#0078d4',
'statusBarItem.remoteForeground': '#ffffff',
'tab.activeBackground': '#1f1f1f',
'tab.activeBorder': '#1f1f1f',
'tab.activeBorderTop': '#0078d4',
'tab.activeForeground': '#ffffff',
'tab.border': '#2b2b2b',
'tab.hoverBackground': '#1f1f1f',
'tab.inactiveBackground': '#181818',
'tab.inactiveForeground': '#9d9d9d',
'tab.lastPinnedBorder': '#cccccc33',
'tab.unfocusedActiveBorder': '#1f1f1f',
'tab.unfocusedActiveBorderTop': '#2b2b2b',
'tab.unfocusedHoverBackground': '#1f1f1f',
'terminal.foreground': '#cccccc',
'terminal.inactiveSelectionBackground': '#3a3d41',
'terminal.tab.activeBorder': '#0078d4',
'textBlockQuote.background': '#2b2b2b',
'textBlockQuote.border': '#616161',
'textCodeBlock.background': '#2b2b2b',
'textLink.activeForeground': '#4daafc',
'textLink.foreground': '#4daafc',
'textPreformat.background': '#3c3c3c',
'textPreformat.foreground': '#d0d0d0',
'textSeparator.foreground': '#21262d',
'titleBar.activeBackground': '#181818',
'titleBar.activeForeground': '#cccccc',
'titleBar.border': '#2b2b2b',
'titleBar.inactiveBackground': '#1f1f1f',
'titleBar.inactiveForeground': '#9d9d9d',
'welcomePage.progress.foreground': '#0078d4',
'welcomePage.tileBackground': '#2b2b2b',
'widget.border': '#313131',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'header',
settings: {
foreground: '#000080',
},
},
{
scope: 'comment',
settings: {
foreground: '#6A9955',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#569CD6',
},
},
{
scope: [
'constant.numeric',
'variable.other.enummember',
'keyword.operator.plus.exponent',
'keyword.operator.minus.exponent',
],
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#646695',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'entity.name.tag.css',
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'invalid',
settings: {
foreground: '#F44747',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
foreground: '#569CD6',
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#569CD6',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'punctuation.definition.quote.begin.markdown',
settings: {
foreground: '#6A9955',
},
},
{
scope: 'punctuation.definition.list.begin.markdown',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'punctuation.definition.tag',
settings: {
foreground: '#808080',
},
},
{
scope: ['meta.preprocessor', 'entity.name.function.preprocessor'],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#569CD6',
},
},
{
scope: ['storage.modifier', 'keyword.operator.noexcept'],
settings: {
foreground: '#569CD6',
},
},
{
scope: ['string', 'meta.embedded.assembly'],
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.tag',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.value',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#D16969',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'keyword',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#D4D4D4',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.alignof',
'keyword.operator.typeid',
'keyword.operator.alignas',
'keyword.operator.instanceof',
'keyword.operator.logical.python',
'keyword.operator.wordlike',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: ['punctuation.section.embedded.begin.php', 'punctuation.section.embedded.end.php'],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#569CD6',
},
},
{
scope: [
'entity.name.function',
'support.function',
'support.constant.handlebars',
'source.powershell variable.other.member',
'entity.name.operator.custom-literal',
],
settings: {
foreground: '#DCDCAA',
},
},
{
scope: [
'support.class',
'support.type',
'entity.name.type',
'entity.name.namespace',
'entity.other.attribute',
'entity.name.scope-resolution',
'entity.name.class',
'storage.type.numeric.go',
'storage.type.byte.go',
'storage.type.boolean.go',
'storage.type.string.go',
'storage.type.uintptr.go',
'storage.type.error.go',
'storage.type.rune.go',
'storage.type.cs',
'storage.type.generic.cs',
'storage.type.modifier.cs',
'storage.type.variable.cs',
'storage.type.annotation.java',
'storage.type.generic.java',
'storage.type.java',
'storage.type.object.array.java',
'storage.type.primitive.array.java',
'storage.type.primitive.java',
'storage.type.token.java',
'storage.type.groovy',
'storage.type.annotation.groovy',
'storage.type.parameters.groovy',
'storage.type.generic.groovy',
'storage.type.object.array.groovy',
'storage.type.primitive.array.groovy',
'storage.type.primitive.groovy',
],
settings: {
foreground: '#4EC9B0',
},
},
{
scope: [
'meta.type.cast.expr',
'meta.type.new.expr',
'support.constant.math',
'support.constant.dom',
'support.constant.json',
'entity.other.inherited-class',
],
settings: {
foreground: '#4EC9B0',
},
},
{
scope: [
'keyword.control',
'source.cpp keyword.operator.new',
'keyword.operator.delete',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
'entity.name.operator',
],
settings: {
foreground: '#C586C0',
},
},
{
scope: [
'variable',
'meta.definition.variable.name',
'support.variable',
'entity.name.variable',
'constant.other.placeholder',
],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: ['variable.other.constant', 'variable.other.enummember'],
settings: {
foreground: '#4FC1FF',
},
},
{
scope: ['meta.object-literal.key'],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#CE9178',
},
},
{
scope: [
'punctuation.definition.group.regexp',
'punctuation.definition.group.assertion.regexp',
'punctuation.definition.character-class.regexp',
'punctuation.character.set.begin.regexp',
'punctuation.character.set.end.regexp',
'keyword.operator.negation.regexp',
'support.other.parenthesis.regexp',
],
settings: {
foreground: '#CE9178',
},
},
{
scope: [
'constant.character.character-class.regexp',
'constant.other.character-class.set.regexp',
'constant.other.character-class.regexp',
'constant.character.set.regexp',
],
settings: {
foreground: '#D16969',
},
},
{
scope: ['keyword.operator.or.regexp', 'keyword.control.anchor.regexp'],
settings: {
foreground: '#DCDCAA',
},
},
{
scope: 'keyword.operator.quantifier.regexp',
settings: {
foreground: '#D7BA7D',
},
},
{
scope: ['constant.character', 'constant.other.option'],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'constant.character.escape',
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'entity.name.label',
settings: {
foreground: '#C8C8C8',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,21 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export { default as darkPlus } from 'shiki/themes/dark-plus.mjs';
export { default as lightPlus } from 'shiki/themes/light-plus.mjs';
export { default as monokai } from 'shiki/themes/monokai.mjs';
export { default as solarizedDark } from 'shiki/themes/solarized-dark.mjs';
export { default as solarizedLight } from 'shiki/themes/solarized-light.mjs';
export { abyss } from './abyss';
export { darkHC } from './dark-hc';
export { darkModern } from './dark-modern';
export { kimbieDark } from './kimbie-dark';
export { lightHC } from './light-hc';
export { lightModern } from './light-modern';
export { monokaiDim } from './monokai-dim';
export { quietLight } from './quiet-light';
export { red } from './red';
export { tomorrowNightBlue } from './tomorrow-night-blue';
export { vsDark } from './vs-dark';
export { vsLight } from './vs-light';
@@ -1,374 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const kimbieDark: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'activityBar.background': '#221a0f',
'activityBar.foreground': '#d3af86',
'badge.background': '#7f5d38',
'button.background': '#6e583b',
'dropdown.background': '#51412c',
'editor.background': '#221a0f',
'editor.foreground': '#d3af86',
'editor.lineHighlightBackground': '#5e452b',
'editor.selectionBackground': '#84613daa',
'editorCursor.foreground': '#d3af86',
'editorGroupHeader.tabsBackground': '#131510',
'editorHoverWidget.background': '#221a14',
'editorLineNumber.activeForeground': '#adadad',
'editorWhitespace.foreground': '#a57a4c',
'editorWidget.background': '#131510',
focusBorder: '#a57a4c',
'input.background': '#51412c',
'inputOption.activeBorder': '#a57a4c',
'inputValidation.errorBackground': '#5f0d0d',
'inputValidation.errorBorder': '#9d2f23',
'inputValidation.infoBackground': '#2b2a42',
'inputValidation.infoBorder': '#1b60a5',
'inputValidation.warningBackground': '#51412c',
'list.activeSelectionBackground': '#7c5021',
'list.highlightForeground': '#e3b583',
'list.hoverBackground': '#7c502166',
'list.inactiveSelectionBackground': '#645342',
'menu.background': '#362712',
'menu.foreground': '#cccccc',
'minimap.selectionHighlight': '#84613daa',
'peekView.border': '#5e452b',
'peekViewEditor.background': '#221a14',
'peekViewEditor.matchHighlightBackground': '#84613daa',
'peekViewResult.background': '#362712',
'peekViewTitle.background': '#362712',
'pickerGroup.border': '#e3b583',
'pickerGroup.foreground': '#e3b583',
'ports.iconRunningProcessForeground': '#369432',
'progressBar.background': '#7f5d38',
'quickInputList.focusBackground': '#7c5021aa',
'selection.background': '#84613daa',
'sideBar.background': '#362712',
'statusBar.background': '#423523',
'statusBar.debuggingBackground': '#423523',
'statusBar.noFolderBackground': '#423523',
'statusBarItem.remoteBackground': '#6e583b',
'tab.inactiveBackground': '#131510',
'tab.lastPinnedBorder': '#51412c',
'titleBar.activeBackground': '#423523',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#D3AF86',
},
},
{
scope: 'variable.parameter.function',
settings: {
foreground: '#D3AF86',
},
},
{
scope: ['comment', 'punctuation.definition.comment'],
settings: {
foreground: '#A57A4C',
},
},
{
scope: [
'punctuation.definition.string',
'punctuation.definition.variable',
'punctuation.definition.string',
'punctuation.definition.parameters',
'punctuation.definition.string',
'punctuation.definition.array',
],
settings: {
foreground: '#D3AF86',
},
},
{
scope: 'none',
settings: {
foreground: '#D3AF86',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#D3AF86',
},
},
{
scope: [
'keyword',
'keyword.control',
'keyword.operator.new.cpp',
'keyword.operator.delete.cpp',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
],
settings: {
foreground: '#98676A',
},
},
{
scope: 'variable',
settings: {
foreground: '#DC3958',
},
},
{
scope: ['entity.name.function', 'meta.require', 'support.function.any-method'],
settings: {
foreground: '#8AB1B0',
},
},
{
scope: [
'support.class',
'entity.name.class',
'entity.name.type',
'entity.name.namespace',
'entity.name.scope-resolution',
],
settings: {
foreground: '#F06431',
},
},
{
scope: 'keyword.other.special-method',
settings: {
foreground: '#8AB1B0',
},
},
{
scope: 'storage',
settings: {
foreground: '#98676A',
},
},
{
scope: 'support.function',
settings: {
foreground: '#7E602C',
},
},
{
scope: ['string', 'constant.other.symbol', 'entity.other.inherited-class'],
settings: {
foreground: '#889B4A',
},
},
{
scope: 'constant.numeric',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'none',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'none',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'constant',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#DC3958',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#F79A32',
},
},
{
scope: ['entity.other.attribute-name.id', 'punctuation.definition.entity'],
settings: {
foreground: '#8AB1B0',
},
},
{
scope: 'meta.selector',
settings: {
foreground: '#98676A',
},
},
{
scope: 'none',
settings: {
foreground: '#F79A32',
},
},
{
scope: ['markup.heading', 'markup.heading.setext', 'punctuation.definition.heading', 'entity.name.section'],
settings: {
foreground: '#8AB1B0',
fontStyle: 'bold',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#F79A32',
},
},
{
scope: ['markup.bold', 'punctuation.definition.bold'],
settings: {
foreground: '#F06431',
fontStyle: 'bold',
},
},
{
scope: ['markup.italic', 'punctuation.definition.italic'],
settings: {
foreground: '#98676A',
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#889B4A',
},
},
{
scope: 'string.other.link',
settings: {
foreground: '#DC3958',
},
},
{
scope: 'meta.link',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'markup.list',
settings: {
foreground: '#DC3958',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#F79A32',
},
},
{
scope: 'meta.separator',
settings: {
foreground: '#D3AF86',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#889B4A',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#DC3958',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#98676A',
},
},
{
scope: 'constant.other.color',
settings: {
foreground: '#7E602C',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#7E602C',
},
},
{
scope: 'constant.character.escape',
settings: {
foreground: '#7E602C',
},
},
{
scope: ['punctuation.section.embedded', 'variable.interpolation'],
settings: {
foreground: '#088649',
},
},
{
scope: 'invalid',
settings: {
foreground: '#DC3958',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,572 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const lightHC: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'light',
colors: {
'actionBar.toggledBackground': '#dddddd',
},
tokenColors: [
{
scope: ['meta.embedded', 'source.groovy.embedded', 'variable.legacy.builtin.python'],
settings: {
foreground: '#292929',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#062F4A',
},
},
{
scope: 'comment',
settings: {
foreground: '#515151',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#0F4A85',
},
},
{
scope: [
'constant.numeric',
'variable.other.enummember',
'keyword.operator.plus.exponent',
'keyword.operator.minus.exponent',
],
settings: {
foreground: '#096D48',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'entity.name.selector',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#264F78',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'invalid',
settings: {
foreground: '#B5200D',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
foreground: '#000080',
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#0F4A85',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#096D48',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#5A5A5A',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#0451A5',
},
},
{
scope: ['punctuation.definition.quote.begin.markdown', 'punctuation.definition.list.begin.markdown'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'punctuation.definition.tag',
settings: {
foreground: '#0F4A85',
},
},
{
scope: ['meta.preprocessor', 'entity.name.function.preprocessor'],
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#B5200D',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#096D48',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'storage',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#0F4A85',
},
},
{
scope: ['storage.modifier', 'keyword.operator.noexcept'],
settings: {
foreground: '#0F4A85',
},
},
{
scope: ['string', 'meta.embedded.assembly'],
settings: {
foreground: '#0F4A85',
},
},
{
scope: [
'string.comment.buffered.block.pug',
'string.quoted.pug',
'string.interpolated.pug',
'string.unquoted.plain.in.yaml',
'string.unquoted.plain.out.yaml',
'string.unquoted.block.yaml',
'string.quoted.single.yaml',
'string.quoted.double.xml',
'string.quoted.single.xml',
'string.unquoted.cdata.xml',
'string.quoted.double.html',
'string.quoted.single.html',
'string.unquoted.html',
'string.quoted.single.handlebars',
'string.quoted.double.handlebars',
],
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#0F4A85',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#000000',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#0451A5',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#264F78',
},
},
{
scope: ['support.type.property-name.json'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'keyword',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#000000',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.alignof',
'keyword.operator.typeid',
'keyword.operator.alignas',
'keyword.operator.instanceof',
'keyword.operator.logical.python',
'keyword.operator.wordlike',
],
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#096D48',
},
},
{
scope: ['punctuation.section.embedded.begin.php', 'punctuation.section.embedded.end.php'],
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#096D48',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#000000',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#0F4A85',
},
},
{
scope: [
'entity.name.function',
'support.function',
'support.constant.handlebars',
'source.powershell variable.other.member',
'entity.name.operator.custom-literal',
],
settings: {
foreground: '#5E2CBC',
},
},
{
scope: [
'support.class',
'support.type',
'entity.name.type',
'entity.name.namespace',
'entity.other.attribute',
'entity.name.scope-resolution',
'entity.name.class',
'storage.type.numeric.go',
'storage.type.byte.go',
'storage.type.boolean.go',
'storage.type.string.go',
'storage.type.uintptr.go',
'storage.type.error.go',
'storage.type.rune.go',
'storage.type.cs',
'storage.type.generic.cs',
'storage.type.modifier.cs',
'storage.type.variable.cs',
'storage.type.annotation.java',
'storage.type.generic.java',
'storage.type.java',
'storage.type.object.array.java',
'storage.type.primitive.array.java',
'storage.type.primitive.java',
'storage.type.token.java',
'storage.type.groovy',
'storage.type.annotation.groovy',
'storage.type.parameters.groovy',
'storage.type.generic.groovy',
'storage.type.object.array.groovy',
'storage.type.primitive.array.groovy',
'storage.type.primitive.groovy',
],
settings: {
foreground: '#185E73',
},
},
{
scope: [
'meta.type.cast.expr',
'meta.type.new.expr',
'support.constant.math',
'support.constant.dom',
'support.constant.json',
'entity.other.inherited-class',
],
settings: {
foreground: '#185E73',
},
},
{
scope: [
'keyword.control',
'source.cpp keyword.operator.new',
'source.cpp keyword.operator.delete',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
'entity.name.operator',
],
settings: {
foreground: '#B5200D',
},
},
{
scope: [
'variable',
'meta.definition.variable.name',
'support.variable',
'entity.name.variable',
'constant.other.placeholder',
],
settings: {
foreground: '#001080',
},
},
{
scope: ['variable.other.constant', 'variable.other.enummember'],
settings: {
foreground: '#02715D',
},
},
{
scope: ['meta.object-literal.key'],
settings: {
foreground: '#001080',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#0451A5',
},
},
{
scope: [
'punctuation.definition.group.regexp',
'punctuation.definition.group.assertion.regexp',
'punctuation.definition.character-class.regexp',
'punctuation.character.set.begin.regexp',
'punctuation.character.set.end.regexp',
'keyword.operator.negation.regexp',
'support.other.parenthesis.regexp',
],
settings: {
foreground: '#D16969',
},
},
{
scope: [
'constant.character.character-class.regexp',
'constant.other.character-class.set.regexp',
'constant.other.character-class.regexp',
'constant.character.set.regexp',
],
settings: {
foreground: '#811F3F',
},
},
{
scope: 'keyword.operator.quantifier.regexp',
settings: {
foreground: '#000000',
},
},
{
scope: ['keyword.operator.or.regexp', 'keyword.control.anchor.regexp'],
settings: {
foreground: '#EE0000',
},
},
{
scope: 'constant.character',
settings: {
foreground: '#0F4A85',
},
},
{
scope: 'constant.character.escape',
settings: {
foreground: '#EE0000',
},
},
{
scope: 'entity.name.label',
settings: {
foreground: '#000000',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#316BCD',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#800080',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#000000',
},
},
],
};
@@ -1,716 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const lightModern: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'light',
colors: {
'actionBar.toggledBackground': '#dddddd',
'activityBar.activeBorder': '#005fb8',
'activityBar.background': '#f8f8f8',
'activityBar.border': '#e5e5e5',
'activityBar.foreground': '#1f1f1f',
'activityBar.inactiveForeground': '#616161',
'activityBarBadge.background': '#005fb8',
'activityBarBadge.foreground': '#ffffff',
'badge.background': '#cccccc',
'badge.foreground': '#3b3b3b',
'button.background': '#005fb8',
'button.border': '#0000001a',
'button.foreground': '#ffffff',
'button.hoverBackground': '#0258a8',
'button.secondaryBackground': '#e5e5e5',
'button.secondaryForeground': '#3b3b3b',
'button.secondaryHoverBackground': '#cccccc',
'chat.slashCommandBackground': '#d2ecff',
'chat.slashCommandForeground': '#306ca2',
'checkbox.background': '#f8f8f8',
'checkbox.border': '#cecece',
descriptionForeground: '#3b3b3b',
'dropdown.background': '#ffffff',
'dropdown.border': '#cecece',
'dropdown.foreground': '#3b3b3b',
'dropdown.listBackground': '#ffffff',
'editor.background': '#ffffff',
'editor.foreground': '#3b3b3b',
'editor.inactiveSelectionBackground': '#e5ebf1',
'editor.selectionHighlightBackground': '#add6ff80',
'editorGroup.border': '#e5e5e5',
'editorGroupHeader.tabsBackground': '#f8f8f8',
'editorGroupHeader.tabsBorder': '#e5e5e5',
'editorGutter.addedBackground': '#2ea043',
'editorGutter.deletedBackground': '#f85149',
'editorGutter.modifiedBackground': '#005fb8',
'editorIndentGuide.activeBackground1': '#939393',
'editorIndentGuide.background1': '#d3d3d3',
'editorLineNumber.activeForeground': '#171184',
'editorLineNumber.foreground': '#6e7681',
'editorOverviewRuler.border': '#e5e5e5',
'editorSuggestWidget.background': '#f8f8f8',
'editorWidget.background': '#f8f8f8',
errorForeground: '#f85149',
focusBorder: '#005fb8',
foreground: '#3b3b3b',
'icon.foreground': '#3b3b3b',
'input.background': '#ffffff',
'input.border': '#cecece',
'input.foreground': '#3b3b3b',
'input.placeholderForeground': '#868686',
'inputOption.activeBackground': '#bed6ed',
'inputOption.activeBorder': '#005fb8',
'inputOption.activeForeground': '#000000',
'keybindingLabel.foreground': '#3b3b3b',
'list.activeSelectionBackground': '#e8e8e8',
'list.activeSelectionForeground': '#000000',
'list.activeSelectionIconForeground': '#000000',
'list.focusAndSelectionOutline': '#005fb8',
'list.hoverBackground': '#f2f2f2',
'menu.border': '#cecece',
'notebook.cellBorderColor': '#e5e5e5',
'notebook.selectedCellBackground': '#c8ddf150',
'notificationCenterHeader.background': '#ffffff',
'notificationCenterHeader.foreground': '#3b3b3b',
'notifications.background': '#ffffff',
'notifications.border': '#e5e5e5',
'notifications.foreground': '#3b3b3b',
'panel.background': '#f8f8f8',
'panel.border': '#e5e5e5',
'panelInput.border': '#e5e5e5',
'panelTitle.activeBorder': '#005fb8',
'panelTitle.activeForeground': '#3b3b3b',
'panelTitle.inactiveForeground': '#3b3b3b',
'peekViewEditor.matchHighlightBackground': '#bb800966',
'peekViewResult.background': '#ffffff',
'peekViewResult.matchHighlightBackground': '#bb800966',
'pickerGroup.border': '#e5e5e5',
'pickerGroup.foreground': '#8b949e',
'ports.iconRunningProcessForeground': '#369432',
'progressBar.background': '#005fb8',
'quickInput.background': '#f8f8f8',
'quickInput.foreground': '#3b3b3b',
'searchEditor.textInputBorder': '#cecece',
'settings.dropdownBackground': '#ffffff',
'settings.dropdownBorder': '#cecece',
'settings.headerForeground': '#1f1f1f',
'settings.modifiedItemIndicator': '#bb800966',
'settings.numberInputBorder': '#cecece',
'settings.textInputBorder': '#cecece',
'sideBar.background': '#f8f8f8',
'sideBar.border': '#e5e5e5',
'sideBar.foreground': '#3b3b3b',
'sideBarSectionHeader.background': '#f8f8f8',
'sideBarSectionHeader.border': '#e5e5e5',
'sideBarSectionHeader.foreground': '#3b3b3b',
'sideBarTitle.foreground': '#3b3b3b',
'statusBar.background': '#f8f8f8',
'statusBar.border': '#e5e5e5',
'statusBar.debuggingBackground': '#fd716c',
'statusBar.debuggingForeground': '#000000',
'statusBar.focusBorder': '#005fb8',
'statusBar.foreground': '#3b3b3b',
'statusBar.noFolderBackground': '#f8f8f8',
'statusBarItem.errorBackground': '#c72e0f',
'statusBarItem.focusBorder': '#005fb8',
'statusBarItem.prominentBackground': '#6e768166',
'statusBarItem.remoteBackground': '#005fb8',
'statusBarItem.remoteForeground': '#ffffff',
'tab.activeBackground': '#ffffff',
'tab.activeBorder': '#f8f8f8',
'tab.activeBorderTop': '#005fb8',
'tab.activeForeground': '#3b3b3b',
'tab.border': '#e5e5e5',
'tab.hoverBackground': '#ffffff',
'tab.inactiveBackground': '#f8f8f8',
'tab.inactiveForeground': '#868686',
'tab.lastPinnedBorder': '#d4d4d4',
'tab.unfocusedActiveBorder': '#f8f8f8',
'tab.unfocusedActiveBorderTop': '#e5e5e5',
'tab.unfocusedHoverBackground': '#f8f8f8',
'terminal.foreground': '#3b3b3b',
'terminal.inactiveSelectionBackground': '#e5ebf1',
'terminal.tab.activeBorder': '#005fb8',
'terminalCursor.foreground': '#005fb8',
'textBlockQuote.background': '#f8f8f8',
'textBlockQuote.border': '#e5e5e5',
'textCodeBlock.background': '#f8f8f8',
'textLink.activeForeground': '#005fb8',
'textLink.foreground': '#005fb8',
'textPreformat.background': '#0000001f',
'textPreformat.foreground': '#3b3b3b',
'textSeparator.foreground': '#21262d',
'titleBar.activeBackground': '#f8f8f8',
'titleBar.activeForeground': '#1e1e1e',
'titleBar.border': '#e5e5e5',
'titleBar.inactiveBackground': '#f8f8f8',
'titleBar.inactiveForeground': '#8b949e',
'welcomePage.tileBackground': '#f3f3f3',
'widget.border': '#e5e5e5',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#000000',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#000080',
},
},
{
scope: 'comment',
settings: {
foreground: '#008000',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#0000FF',
},
},
{
scope: [
'constant.numeric',
'variable.other.enummember',
'keyword.operator.plus.exponent',
'keyword.operator.minus.exponent',
],
settings: {
foreground: '#098658',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#800000',
},
},
{
scope: 'entity.name.selector',
settings: {
foreground: '#800000',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#E50000',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#800000',
},
},
{
scope: 'invalid',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
foreground: '#000080',
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#800000',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#098658',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#A31515',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#0451A5',
},
},
{
scope: ['punctuation.definition.quote.begin.markdown', 'punctuation.definition.list.begin.markdown'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#800000',
},
},
{
scope: 'punctuation.definition.tag',
settings: {
foreground: '#800000',
},
},
{
scope: ['meta.preprocessor', 'entity.name.function.preprocessor'],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#A31515',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#098658',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'storage',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#0000FF',
},
},
{
scope: ['storage.modifier', 'keyword.operator.noexcept'],
settings: {
foreground: '#0000FF',
},
},
{
scope: ['string', 'meta.embedded.assembly'],
settings: {
foreground: '#A31515',
},
},
{
scope: [
'string.comment.buffered.block.pug',
'string.quoted.pug',
'string.interpolated.pug',
'string.unquoted.plain.in.yaml',
'string.unquoted.plain.out.yaml',
'string.unquoted.block.yaml',
'string.quoted.single.yaml',
'string.quoted.double.xml',
'string.quoted.single.xml',
'string.unquoted.cdata.xml',
'string.quoted.double.html',
'string.quoted.single.html',
'string.unquoted.html',
'string.quoted.single.handlebars',
'string.quoted.double.handlebars',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#000000',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#0451A5',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#E50000',
},
},
{
scope: ['support.type.property-name.json'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'keyword',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#000000',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.alignof',
'keyword.operator.typeid',
'keyword.operator.alignas',
'keyword.operator.instanceof',
'keyword.operator.logical.python',
'keyword.operator.wordlike',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#098658',
},
},
{
scope: ['punctuation.section.embedded.begin.php', 'punctuation.section.embedded.end.php'],
settings: {
foreground: '#800000',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#098658',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#000000',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#0000FF',
},
},
{
scope: [
'entity.name.function',
'support.function',
'support.constant.handlebars',
'source.powershell variable.other.member',
'entity.name.operator.custom-literal',
],
settings: {
foreground: '#795E26',
},
},
{
scope: [
'support.class',
'support.type',
'entity.name.type',
'entity.name.namespace',
'entity.other.attribute',
'entity.name.scope-resolution',
'entity.name.class',
'storage.type.numeric.go',
'storage.type.byte.go',
'storage.type.boolean.go',
'storage.type.string.go',
'storage.type.uintptr.go',
'storage.type.error.go',
'storage.type.rune.go',
'storage.type.cs',
'storage.type.generic.cs',
'storage.type.modifier.cs',
'storage.type.variable.cs',
'storage.type.annotation.java',
'storage.type.generic.java',
'storage.type.java',
'storage.type.object.array.java',
'storage.type.primitive.array.java',
'storage.type.primitive.java',
'storage.type.token.java',
'storage.type.groovy',
'storage.type.annotation.groovy',
'storage.type.parameters.groovy',
'storage.type.generic.groovy',
'storage.type.object.array.groovy',
'storage.type.primitive.array.groovy',
'storage.type.primitive.groovy',
],
settings: {
foreground: '#267F99',
},
},
{
scope: [
'meta.type.cast.expr',
'meta.type.new.expr',
'support.constant.math',
'support.constant.dom',
'support.constant.json',
'entity.other.inherited-class',
],
settings: {
foreground: '#267F99',
},
},
{
scope: [
'keyword.control',
'source.cpp keyword.operator.new',
'source.cpp keyword.operator.delete',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
'entity.name.operator',
],
settings: {
foreground: '#AF00DB',
},
},
{
scope: [
'variable',
'meta.definition.variable.name',
'support.variable',
'entity.name.variable',
'constant.other.placeholder',
],
settings: {
foreground: '#001080',
},
},
{
scope: ['variable.other.constant', 'variable.other.enummember'],
settings: {
foreground: '#0070C1',
},
},
{
scope: ['meta.object-literal.key'],
settings: {
foreground: '#001080',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#0451A5',
},
},
{
scope: [
'punctuation.definition.group.regexp',
'punctuation.definition.group.assertion.regexp',
'punctuation.definition.character-class.regexp',
'punctuation.character.set.begin.regexp',
'punctuation.character.set.end.regexp',
'keyword.operator.negation.regexp',
'support.other.parenthesis.regexp',
],
settings: {
foreground: '#D16969',
},
},
{
scope: [
'constant.character.character-class.regexp',
'constant.other.character-class.set.regexp',
'constant.other.character-class.regexp',
'constant.character.set.regexp',
],
settings: {
foreground: '#811F3F',
},
},
{
scope: 'keyword.operator.quantifier.regexp',
settings: {
foreground: '#000000',
},
},
{
scope: ['keyword.operator.or.regexp', 'keyword.control.anchor.regexp'],
settings: {
foreground: '#EE0000',
},
},
{
scope: ['constant.character', 'constant.other.option'],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'constant.character.escape',
settings: {
foreground: '#EE0000',
},
},
{
scope: 'entity.name.label',
settings: {
foreground: '#000000',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#000000',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#316BCD',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#800080',
},
},
],
};
@@ -1,573 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const monokaiDim: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'activityBar.background': '#353535',
'activityBar.foreground': '#ffffff',
'activityBarBadge.background': '#3655b5',
'button.background': '#565656',
'dropdown.background': '#525252',
'editor.background': '#1e1e1e',
'editor.foreground': '#c5c8c6',
'editor.lineHighlightBackground': '#303030',
'editor.selectionBackground': '#676b7180',
'editor.selectionHighlightBackground': '#575b6180',
'editor.wordHighlightBackground': '#4747a180',
'editor.wordHighlightStrongBackground': '#6767ce80',
'editorCursor.foreground': '#c07020',
'editorGroupHeader.tabsBackground': '#282828',
'editorIndentGuide.activeBackground': '#707057',
'editorIndentGuide.background': '#505037',
'editorLineNumber.activeForeground': '#949494',
'editorWhitespace.foreground': '#505037',
focusBorder: '#3655b5',
'inputOption.activeBorder': '#3655b5',
'list.activeSelectionBackground': '#707070',
'list.highlightForeground': '#e58520',
'list.hoverBackground': '#444444',
'list.inactiveSelectionBackground': '#4e4e4e',
'menu.background': '#272727',
'menu.foreground': '#cccccc',
'minimap.selectionHighlight': '#676b7180',
'panelTitle.activeForeground': '#ffffff',
'peekView.border': '#3655b5',
'pickerGroup.foreground': '#b0b0b0',
'ports.iconRunningProcessForeground': '#cccccc',
'quickInputList.focusBackground': '#707070',
'sideBar.background': '#272727',
'sideBarSectionHeader.background': '#505050',
'statusBar.background': '#505050',
'statusBar.debuggingBackground': '#505050',
'statusBar.noFolderBackground': '#505050',
'statusBarItem.remoteBackground': '#3655b5',
'tab.border': '#303030',
'tab.inactiveBackground': '#404040',
'tab.inactiveForeground': '#d8d8d8',
'tab.lastPinnedBorder': '#505050',
'terminal.ansiBlack': '#1e1e1e',
'terminal.ansiBlue': '#6a7ec8',
'terminal.ansiBrightBlack': '#666666',
'terminal.ansiBrightBlue': '#819aff',
'terminal.ansiBrightCyan': '#66d9ef',
'terminal.ansiBrightGreen': '#a6e22e',
'terminal.ansiBrightMagenta': '#ae81ff',
'terminal.ansiBrightRed': '#f92672',
'terminal.ansiBrightWhite': '#f8f8f2',
'terminal.ansiBrightYellow': '#e2e22e',
'terminal.ansiCyan': '#56adbc',
'terminal.ansiGreen': '#86b42b',
'terminal.ansiMagenta': '#8c6bc8',
'terminal.ansiRed': '#c4265e',
'terminal.ansiWhite': '#e3e3dd',
'terminal.ansiYellow': '#b3b42b',
'terminal.inactiveSelectionBackground': '#676b7140',
'titleBar.activeBackground': '#505050',
},
tokenColors: [
{
scope: ['meta.embedded', 'source.groovy.embedded', 'variable.legacy.builtin.python'],
settings: {
foreground: '#C5C8C6',
},
},
{
scope: 'comment',
settings: {
foreground: '#9A9B99',
fontStyle: '',
},
},
{
scope: 'string',
settings: {
foreground: '#9AA83A',
fontStyle: '',
},
},
{
scope: 'string source',
settings: {
foreground: '#D08442',
fontStyle: '',
},
},
{
scope: 'constant.numeric',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#408080',
fontStyle: '',
},
},
{
scope: 'constant.character, constant.other',
settings: {
foreground: '#8080FF',
fontStyle: '',
},
},
{
scope: 'keyword',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'support',
settings: {
foreground: '#C7444A',
fontStyle: '',
},
},
{
scope: 'storage',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution',
settings: {
foreground: '#9B0000',
fontStyle: '',
},
},
{
scope: 'entity.other.inherited-class',
settings: {
foreground: '#C7444A',
fontStyle: '',
},
},
{
scope: 'entity.name.function',
settings: {
foreground: '#CE6700',
fontStyle: '',
},
},
{
scope: 'variable.parameter',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'support.function',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'keyword',
settings: {
foreground: '#676867',
fontStyle: '',
},
},
{
scope: 'variable.other, variable.js, punctuation.separator.variable',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html',
settings: {
foreground: '#008200',
fontStyle: '',
},
},
{
scope: 'invalid',
settings: {
foreground: '#FF0B00',
fontStyle: '',
},
},
{
scope: 'variable.other.php, variable.other.normal',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'meta.function-call.object',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'variable.other.property',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: [
'keyword.control',
'keyword.operator.new.cpp',
'keyword.operator.delete.cpp',
'keyword.other.using',
'keyword.other.directive.using',
'keyword.other.operator',
],
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'meta.tag',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'meta.doctype, meta.tag.sgml-declaration.doctype, meta.tag.sgml.doctype',
settings: {
foreground: '#9AA83A',
fontStyle: '',
},
},
{
scope: 'meta.tag.inline source, text.html.php.source',
settings: {
foreground: '#9AA83A',
fontStyle: '',
},
},
{
scope: 'meta.tag.other, entity.name.tag.style, entity.name.tag.script, meta.tag.block.script, source.js.embedded punctuation.definition.tag.html, source.css.embedded punctuation.definition.tag.html',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'entity.other.attribute-name, meta.tag punctuation.definition.string',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'meta.tag string -source -punctuation, text source text meta.tag string -punctuation',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'meta.toc-list.id',
settings: {
foreground: '#9AA83A',
},
},
{
scope: 'string.quoted.double.html, punctuation.definition.string.begin.html, punctuation.definition.string.end.html, punctuation.definition.string.end.html source, string.quoted.double.html source',
settings: {
foreground: '#9AA83A',
fontStyle: '',
},
},
{
scope: 'punctuation.definition.tag.html, punctuation.definition.tag.begin, punctuation.definition.tag.end',
settings: {
foreground: '#6089B4',
fontStyle: '',
},
},
{
scope: 'meta.selector.css entity.other.attribute-name.id',
settings: {
foreground: '#9872A2',
fontStyle: '',
},
},
{
scope: 'support.type.property-name.css',
settings: {
foreground: '#676867',
fontStyle: '',
},
},
{
scope: 'meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css',
settings: {
foreground: '#C7444A',
fontStyle: '',
},
},
{
scope: 'variable.language.js',
settings: {
foreground: '#CC555A',
},
},
{
scope: ['punctuation.definition.template-expression', 'punctuation.section.embedded.coffee'],
settings: {
foreground: '#D08442',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#C5C8C6',
},
},
{
scope: 'meta.function-call.object.php',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'punctuation.definition.string.end.php, punctuation.definition.string.begin.php',
settings: {
foreground: '#9AA83A',
},
},
{
scope: 'source.php.embedded.line.html',
settings: {
foreground: '#676867',
},
},
{
scope: 'punctuation.section.embedded.begin.php, punctuation.section.embedded.end.php',
settings: {
foreground: '#D08442',
fontStyle: '',
},
},
{
scope: 'constant.other.symbol.ruby',
settings: {
foreground: '#9AA83A',
fontStyle: '',
},
},
{
scope: 'variable.language.ruby',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'keyword.other.special-method.ruby',
settings: {
foreground: '#D9B700',
fontStyle: '',
},
},
{
scope: ['punctuation.section.embedded.begin.ruby', 'punctuation.section.embedded.end.ruby'],
settings: {
foreground: '#D08442',
},
},
{
scope: 'keyword.other.DML.sql',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'meta.diff, meta.diff.header',
settings: {
foreground: '#E0EDDD',
fontStyle: 'italic',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#DC322F',
fontStyle: '',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#CB4B16',
fontStyle: '',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#219186',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#9872A2',
},
},
{
scope: 'markup.list',
settings: {
foreground: '#9AA83A',
},
},
{
scope: 'markup.bold, markup.italic',
settings: {
foreground: '#6089B4',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#FF0080',
fontStyle: '',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#D0B344',
},
},
{
scope: 'markup.heading.setext',
settings: {
foreground: '#D0B344',
fontStyle: '',
},
},
{
scope: 'markup.heading.markdown',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.quote.markdown',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.bold.markdown',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'string.other.link.title.markdown,string.other.link.description.markdown',
settings: {
foreground: '#AE81FF',
},
},
{
scope: 'markup.underline.link.markdown,markup.underline.link.image.markdown',
settings: {},
},
{
scope: 'markup.italic.markdown',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.list.unnumbered.markdown, markup.list.numbered.markdown',
settings: {},
},
{
scope: ['punctuation.definition.list.begin.markdown'],
settings: {},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#C7444A',
},
},
],
};
@@ -1,465 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const quietLight: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'light',
colors: {
'activityBar.background': '#ededf5',
'activityBar.foreground': '#705697',
'activityBarBadge.background': '#705697',
'badge.background': '#705697aa',
'button.background': '#705697',
'dropdown.background': '#f5f5f5',
'editor.background': '#f5f5f5',
'editor.findMatchBackground': '#bf9cac',
'editor.findMatchHighlightBackground': '#edc9d899',
'editor.lineHighlightBackground': '#e4f6d4',
'editor.selectionBackground': '#c9d0d9',
'editorCursor.foreground': '#54494b',
'editorGroup.dropBackground': '#c9d0d988',
'editorIndentGuide.activeBackground': '#777777b0',
'editorIndentGuide.background': '#aaaaaa60',
'editorLineNumber.activeForeground': '#9769dc',
'editorLineNumber.foreground': '#6d705b',
'editorWhitespace.foreground': '#aaaaaa',
errorForeground: '#f1897f',
focusBorder: '#9769dc',
'inputOption.activeBorder': '#adafb7',
'inputValidation.errorBackground': '#ffeaea',
'inputValidation.errorBorder': '#f1897f',
'inputValidation.infoBackground': '#f2fcff',
'inputValidation.infoBorder': '#4ec1e5',
'inputValidation.warningBackground': '#fffee2',
'inputValidation.warningBorder': '#ffe055',
'list.activeSelectionBackground': '#c4d9b1',
'list.activeSelectionForeground': '#6c6c6c',
'list.highlightForeground': '#9769dc',
'list.hoverBackground': '#e0e0e0',
'list.inactiveSelectionBackground': '#d3dbcd',
'minimap.selectionHighlight': '#c9d0d9',
'panel.background': '#f5f5f5',
'peekView.border': '#705697',
'peekViewEditor.background': '#f2f8fc',
'peekViewEditor.matchHighlightBackground': '#c2dfe3',
'peekViewResult.background': '#f2f8fc',
'peekViewResult.matchHighlightBackground': '#93c6d6',
'peekViewTitle.background': '#f2f8fc',
'pickerGroup.border': '#749351',
'pickerGroup.foreground': '#a6b39b',
'ports.iconRunningProcessForeground': '#749351',
'progressBar.background': '#705697',
'quickInputList.focusBackground': '#cadeb9',
'selection.background': '#c9d0d9',
'sideBar.background': '#f2f2f2',
'sideBarSectionHeader.background': '#ede8ef',
'statusBar.background': '#705697',
'statusBar.debuggingBackground': '#705697',
'statusBar.noFolderBackground': '#705697',
'statusBarItem.remoteBackground': '#4e3c69',
'tab.lastPinnedBorder': '#c9d0d9',
'titleBar.activeBackground': '#c4b7d7',
'walkThrough.embeddedEditorBackground': '#00000014',
'welcomePage.tileBackground': '#f0f0f7',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#333333',
},
},
{
scope: ['comment', 'punctuation.definition.comment'],
settings: {
foreground: '#AAAAAA',
fontStyle: 'italic',
},
},
{
scope: 'comment.block.preprocessor',
settings: {
foreground: '#AAAAAA',
fontStyle: '',
},
},
{
scope: [
'comment.documentation',
'comment.block.documentation',
'comment.block.documentation punctuation.definition.comment ',
],
settings: {
foreground: '#448C27',
},
},
{
scope: 'invalid',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'invalid.illegal',
settings: {
foreground: '#660000',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#777777',
},
},
{
scope: ['keyword', 'storage'],
settings: {
foreground: '#4B69C6',
},
},
{
scope: ['storage.type', 'support.type'],
settings: {
foreground: '#7A3E9D',
},
},
{
scope: ['constant.language', 'support.constant', 'variable.language'],
settings: {
foreground: '#9C5D27',
},
},
{
scope: ['variable', 'support.variable'],
settings: {
foreground: '#7A3E9D',
},
},
{
scope: ['entity.name.function', 'support.function'],
settings: {
foreground: '#AA3731',
fontStyle: 'bold',
},
},
{
scope: [
'entity.name.type',
'entity.name.namespace',
'entity.name.scope-resolution',
'entity.other.inherited-class',
'support.class',
],
settings: {
foreground: '#7A3E9D',
fontStyle: 'bold',
},
},
{
scope: 'entity.name.exception',
settings: {
foreground: '#660000',
},
},
{
scope: 'entity.name.section',
settings: {
fontStyle: 'bold',
},
},
{
scope: ['constant.numeric', 'constant.character', 'constant'],
settings: {
foreground: '#9C5D27',
},
},
{
scope: 'string',
settings: {
foreground: '#448C27',
},
},
{
scope: 'constant.character.escape',
settings: {
foreground: '#777777',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#4B69C6',
},
},
{
scope: 'constant.other.symbol',
settings: {
foreground: '#9C5D27',
},
},
{
scope: 'punctuation',
settings: {
foreground: '#777777',
},
},
{
scope: [
'meta.tag.sgml.doctype',
'meta.tag.sgml.doctype string',
'meta.tag.sgml.doctype entity.name.tag',
'meta.tag.sgml punctuation.definition.tag.html',
],
settings: {
foreground: '#AAAAAA',
},
},
{
scope: [
'meta.tag',
'punctuation.definition.tag.html',
'punctuation.definition.tag.begin.html',
'punctuation.definition.tag.end.html',
],
settings: {
foreground: '#91B3E0',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#4B69C6',
},
},
{
scope: ['meta.tag entity.other.attribute-name', 'entity.other.attribute-name.html'],
settings: {
foreground: '#8190A0',
fontStyle: 'italic',
},
},
{
scope: ['constant.character.entity', 'punctuation.definition.entity'],
settings: {
foreground: '#9C5D27',
},
},
{
scope: ['meta.selector', 'meta.selector entity', 'meta.selector entity punctuation', 'entity.name.tag.css'],
settings: {
foreground: '#7A3E9D',
},
},
{
scope: ['meta.property-name', 'support.type.property-name'],
settings: {
foreground: '#9C5D27',
},
},
{
scope: ['meta.property-value', 'meta.property-value constant.other', 'support.constant.property-value'],
settings: {
foreground: '#448C27',
},
},
{
scope: 'keyword.other.important',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#000000',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#000000',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.error',
settings: {
foreground: '#660000',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#000000',
},
},
{
scope: 'meta.link',
settings: {
foreground: '#4B69C6',
},
},
{
scope: ['markup.output', 'markup.raw'],
settings: {
foreground: '#777777',
},
},
{
scope: 'markup.prompt',
settings: {
foreground: '#777777',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#AA3731',
},
},
{
scope: 'markup.bold',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.traceback',
settings: {
foreground: '#660000',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#7A3E9D',
},
},
{
scope: 'markup.list',
settings: {
foreground: '#4B69C6',
},
},
{
scope: ['markup.bold', 'markup.italic'],
settings: {
foreground: '#448C27',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#9C5D27',
fontStyle: '',
},
},
{
scope: ['meta.diff.range', 'meta.diff.index', 'meta.separator'],
settings: {
foreground: '#434343',
},
},
{
scope: ['meta.diff.header.from-file', 'punctuation.definition.from-file.diff'],
settings: {
foreground: '#4B69C6',
},
},
{
scope: ['meta.diff.header.to-file', 'punctuation.definition.to-file.diff'],
settings: {
foreground: '#4B69C6',
},
},
{
scope: 'markup.deleted.diff',
settings: {
foreground: '#C73D20',
},
},
{
scope: 'markup.changed.diff',
settings: {
foreground: '#9C5D27',
},
},
{
scope: 'markup.inserted.diff',
settings: {
foreground: '#448C27',
},
},
{
scope: [
'punctuation.definition.tag.js',
'punctuation.definition.tag.begin.js',
'punctuation.definition.tag.end.js',
],
settings: {
foreground: '#91B3E0',
},
},
{
scope: 'meta.jsx.children.js',
settings: {
foreground: '#333333',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#000000',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#316BCD',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#800080',
},
},
],
};
@@ -1,376 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const red: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'activityBar.background': '#580000',
'badge.background': '#cc3333',
'button.background': '#883333',
'debugToolBar.background': '#660000',
'dropdown.background': '#580000',
'editor.background': '#390000',
'editor.foreground': '#f8f8f8',
'editor.hoverHighlightBackground': '#ff000044',
'editor.lineHighlightBackground': '#ff000033',
'editor.selectionBackground': '#750000',
'editor.selectionHighlightBackground': '#f5500039',
'editorCursor.foreground': '#970000',
'editorGroup.border': '#ff666633',
'editorGroupHeader.tabsBackground': '#330000',
'editorHoverWidget.background': '#300000',
'editorLineNumber.activeForeground': '#ffbbbb88',
'editorLineNumber.foreground': '#ff777788',
'editorLink.activeForeground': '#ffd0aa',
'editorSuggestWidget.background': '#300000',
'editorSuggestWidget.border': '#220000',
'editorWhitespace.foreground': '#c10000',
'editorWidget.background': '#300000',
errorForeground: '#ffeaea',
'extensionButton.prominentBackground': '#cc3333',
'extensionButton.prominentHoverBackground': '#cc333388',
focusBorder: '#ff6666aa',
'input.background': '#580000',
'inputOption.activeBorder': '#cc0000',
'inputValidation.infoBackground': '#550000',
'inputValidation.infoBorder': '#db7e58',
'list.activeSelectionBackground': '#880000',
'list.dropBackground': '#662222',
'list.highlightForeground': '#ff4444',
'list.hoverBackground': '#800000',
'list.inactiveSelectionBackground': '#770000',
'minimap.selectionHighlight': '#750000',
'peekView.border': '#ff000044',
'peekViewEditor.background': '#300000',
'peekViewResult.background': '#400000',
'peekViewTitle.background': '#550000',
'pickerGroup.border': '#ff000033',
'pickerGroup.foreground': '#cc9999',
'ports.iconRunningProcessForeground': '#db7e58',
'progressBar.background': '#cc3333',
'quickInputList.focusBackground': '#660000',
'selection.background': '#ff777788',
'sideBar.background': '#330000',
'statusBar.background': '#700000',
'statusBar.noFolderBackground': '#700000',
'statusBarItem.remoteBackground': '#cc3333',
'tab.activeBackground': '#490000',
'tab.inactiveBackground': '#300a0a',
'tab.lastPinnedBorder': '#ff000044',
'titleBar.activeBackground': '#770000',
'titleBar.inactiveBackground': '#772222',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#F8F8F8',
},
},
{
scope: 'comment',
settings: {
foreground: '#E7C0C0',
fontStyle: 'italic',
},
},
{
scope: 'constant',
settings: {
foreground: '#994646',
fontStyle: '',
},
},
{
scope: 'keyword',
settings: {
foreground: '#F12727',
fontStyle: '',
},
},
{
scope: 'entity',
settings: {
foreground: '#FEC758',
fontStyle: '',
},
},
{
scope: 'storage',
settings: {
foreground: '#FF6262',
fontStyle: 'bold',
},
},
{
scope: 'string',
settings: {
foreground: '#CD8D8D',
fontStyle: '',
},
},
{
scope: 'support',
settings: {
foreground: '#9DF39F',
fontStyle: '',
},
},
{
scope: 'variable',
settings: {
foreground: '#FB9A4B',
fontStyle: 'italic',
},
},
{
scope: 'invalid',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'entity.other.inherited-class',
settings: {
foreground: '#AA5507',
fontStyle: 'underline',
},
},
{
scope: 'constant.character',
settings: {
foreground: '#EC0D1E',
},
},
{
scope: ['string constant', 'constant.character.escape'],
settings: {
foreground: '#FFE862',
fontStyle: '',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#FFB454',
},
},
{
scope: 'string variable',
settings: {
foreground: '#EDEF7D',
},
},
{
scope: 'support.function',
settings: {
foreground: '#FFB454',
fontStyle: '',
},
},
{
scope: ['support.constant', 'support.variable'],
settings: {
foreground: '#EB939A',
fontStyle: '',
},
},
{
scope: [
'declaration.sgml.html declaration.doctype',
'declaration.sgml.html declaration.doctype entity',
'declaration.sgml.html declaration.doctype string',
'declaration.xml-processing',
'declaration.xml-processing entity',
'declaration.xml-processing string',
],
settings: {
foreground: '#73817D',
fontStyle: '',
},
},
{
scope: ['declaration.tag', 'declaration.tag entity', 'meta.tag', 'meta.tag entity'],
settings: {
foreground: '#EC0D1E',
fontStyle: '',
},
},
{
scope: 'meta.selector.css entity.name.tag',
settings: {
foreground: '#AA5507',
fontStyle: '',
},
},
{
scope: 'meta.selector.css entity.other.attribute-name.id',
settings: {
foreground: '#FEC758',
},
},
{
scope: 'meta.selector.css entity.other.attribute-name.class',
settings: {
foreground: '#41A83E',
fontStyle: '',
},
},
{
scope: 'support.type.property-name.css',
settings: {
foreground: '#96DD3B',
fontStyle: '',
},
},
{
scope: [
'meta.property-group support.constant.property-value.css',
'meta.property-value support.constant.property-value.css',
],
settings: {
foreground: '#FFE862',
fontStyle: 'italic',
},
},
{
scope: ['meta.property-value support.constant.named-color.css', 'meta.property-value constant'],
settings: {
foreground: '#FFE862',
fontStyle: '',
},
},
{
scope: 'meta.preprocessor.at-rule keyword.control.at-rule',
settings: {
foreground: '#FD6209',
},
},
{
scope: 'meta.constructor.argument.css',
settings: {
foreground: '#EC9799',
fontStyle: '',
},
},
{
scope: ['meta.diff', 'meta.diff.header'],
settings: {
foreground: '#F8F8F8',
fontStyle: 'italic',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#EC9799',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#F8F8F8',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#41A83E',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#F12727',
},
},
{
scope: 'markup.list',
settings: {
foreground: '#FF6262',
},
},
{
scope: ['markup.bold', 'markup.italic'],
settings: {
foreground: '#FB9A4B',
},
},
{
scope: 'markup.bold',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#CD8D8D',
fontStyle: '',
},
},
{
scope: ['markup.heading', 'markup.heading.setext', 'punctuation.definition.heading', 'entity.name.section'],
settings: {
foreground: '#FEC758',
fontStyle: 'bold',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
'.format.placeholder',
],
settings: {
foreground: '#EC0D1E',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,265 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const tomorrowNightBlue: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'activityBar.background': '#001733',
'badge.background': '#bbdaffcc',
'badge.foreground': '#001733',
'debugToolBar.background': '#001c40',
'dropdown.background': '#001733',
'editor.background': '#002451',
'editor.foreground': '#ffffff',
'editor.lineHighlightBackground': '#00346e',
'editor.selectionBackground': '#003f8e',
'editorCursor.foreground': '#ffffff',
'editorGroup.border': '#404f7d',
'editorGroup.dropBackground': '#25375daa',
'editorGroupHeader.tabsBackground': '#001733',
'editorHoverWidget.background': '#001c40',
'editorHoverWidget.border': '#ffffff44',
'editorLineNumber.activeForeground': '#949494',
'editorWhitespace.foreground': '#404f7d',
'editorWidget.background': '#001c40',
errorForeground: '#a92049',
focusBorder: '#bbdaff',
'input.background': '#001733',
'list.activeSelectionBackground': '#ffffff60',
'list.highlightForeground': '#bbdaff',
'list.hoverBackground': '#ffffff30',
'list.inactiveSelectionBackground': '#ffffff40',
'minimap.selectionHighlight': '#003f8e',
'peekViewResult.background': '#001c40',
'pickerGroup.foreground': '#bbdaff',
'ports.iconRunningProcessForeground': '#bbdaff',
'progressBar.background': '#bbdaffcc',
'quickInputList.focusBackground': '#ffffff60',
'sideBar.background': '#001c40',
'statusBar.background': '#001126',
'statusBar.debuggingBackground': '#001126',
'statusBar.noFolderBackground': '#001126',
'statusBarItem.remoteBackground': '#0e639c',
'tab.inactiveBackground': '#001c40',
'tab.lastPinnedBorder': '#007acc80',
'terminal.ansiBlack': '#111111',
'terminal.ansiBlue': '#bbdaff',
'terminal.ansiBrightBlack': '#333333',
'terminal.ansiBrightBlue': '#80baff',
'terminal.ansiBrightCyan': '#78ffff',
'terminal.ansiBrightGreen': '#b8f171',
'terminal.ansiBrightMagenta': '#d778ff',
'terminal.ansiBrightRed': '#ff7882',
'terminal.ansiBrightWhite': '#ffffff',
'terminal.ansiBrightYellow': '#ffe580',
'terminal.ansiCyan': '#99ffff',
'terminal.ansiGreen': '#d1f1a9',
'terminal.ansiMagenta': '#ebbbff',
'terminal.ansiRed': '#ff9da4',
'terminal.ansiWhite': '#cccccc',
'terminal.ansiYellow': '#ffeead',
'titleBar.activeBackground': '#001126',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'meta.jsx.children',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'comment',
settings: {
foreground: '#7285B7',
},
},
{
scope: 'keyword.operator.class, keyword.operator, constant.other, source.php.embedded.line',
settings: {
foreground: '#FFFFFF',
fontStyle: '',
},
},
{
scope: 'variable, support.other.variable, string.other.link, string.regexp, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag, markup.deleted.git_gutter',
settings: {
foreground: '#FF9DA4',
},
},
{
scope: 'constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit',
settings: {
foreground: '#FFC58F',
fontStyle: '',
},
},
{
scope: 'entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution, support.type, support.class',
settings: {
foreground: '#FFEEAD',
fontStyle: '',
},
},
{
scope: 'string, constant.other.symbol, entity.other.inherited-class, markup.heading, markup.inserted.git_gutter',
settings: {
foreground: '#D1F1A9',
fontStyle: '',
},
},
{
scope: 'keyword.operator, constant.other.color',
settings: {
foreground: '#99FFFF',
},
},
{
scope: 'entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level, markup.changed.git_gutter',
settings: {
foreground: '#BBDAFF',
fontStyle: '',
},
},
{
scope: 'keyword, storage, storage.type, entity.name.tag.css',
settings: {
foreground: '#EBBBFF',
fontStyle: '',
},
},
{
scope: 'invalid',
settings: {
foreground: '#A92049',
fontStyle: '',
},
},
{
scope: 'meta.separator',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'invalid.deprecated',
settings: {
foreground: '#CD9731',
fontStyle: '',
},
},
{
scope: 'markup.inserted.diff, markup.deleted.diff, meta.diff.header.to-file, meta.diff.header.from-file',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'markup.inserted.diff, meta.diff.header.to-file',
settings: {
foreground: '#718C00',
},
},
{
scope: 'markup.deleted.diff, meta.diff.header.from-file',
settings: {
foreground: '#C82829',
},
},
{
scope: 'meta.diff.header.from-file, meta.diff.header.to-file',
settings: {
foreground: '#4271AE',
},
},
{
scope: 'meta.diff.range',
settings: {
foreground: '#3E999F',
fontStyle: 'italic',
},
},
{
scope: 'markup.quote',
settings: {
foreground: '#FFC58F',
},
},
{
scope: 'markup.list',
settings: {
foreground: '#BBDAFF',
},
},
{
scope: 'markup.bold, markup.italic',
settings: {
foreground: '#FFC58F',
},
},
{
scope: 'markup.bold',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#FF9DA4',
fontStyle: '',
},
},
{
scope: 'markup.heading',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,412 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const vsDark: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'dark',
colors: {
'actionBar.toggledBackground': '#383a49',
'activityBarBadge.background': '#007acc',
'checkbox.border': '#6b6b6b',
'editor.background': '#1e1e1e',
'editor.foreground': '#d4d4d4',
'editor.inactiveSelectionBackground': '#3a3d41',
'editor.selectionHighlightBackground': '#add6ff26',
'editorIndentGuide.activeBackground1': '#707070',
'editorIndentGuide.background1': '#404040',
'input.placeholderForeground': '#a6a6a6',
'list.activeSelectionIconForeground': '#ffffff',
'list.dropBackground': '#383b3d',
'menu.background': '#252526',
'menu.border': '#454545',
'menu.foreground': '#cccccc',
'menu.separatorBackground': '#454545',
'ports.iconRunningProcessForeground': '#369432',
'sideBarSectionHeader.background': '#00000000',
'sideBarSectionHeader.border': '#cccccc33',
'sideBarTitle.foreground': '#bbbbbb',
'statusBarItem.remoteBackground': '#16825d',
'statusBarItem.remoteForeground': '#ffffff',
'tab.lastPinnedBorder': '#cccccc33',
'terminal.inactiveSelectionBackground': '#3a3d41',
'widget.border': '#303031',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'header',
settings: {
foreground: '#000080',
},
},
{
scope: 'comment',
settings: {
foreground: '#6A9955',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#569CD6',
},
},
{
scope: [
'constant.numeric',
'variable.other.enummember',
'keyword.operator.plus.exponent',
'keyword.operator.minus.exponent',
],
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#646695',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'entity.name.tag.css',
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#D7BA7D',
},
},
{
scope: 'invalid',
settings: {
foreground: '#F44747',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
foreground: '#569CD6',
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#569CD6',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'punctuation.definition.quote.begin.markdown',
settings: {
foreground: '#6A9955',
},
},
{
scope: 'punctuation.definition.list.begin.markdown',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'punctuation.definition.tag',
settings: {
foreground: '#808080',
},
},
{
scope: ['meta.preprocessor', 'entity.name.function.preprocessor'],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#569CD6',
},
},
{
scope: ['storage.modifier', 'keyword.operator.noexcept'],
settings: {
foreground: '#569CD6',
},
},
{
scope: ['string', 'meta.embedded.assembly'],
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.tag',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.value',
settings: {
foreground: '#CE9178',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#D16969',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'keyword',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#D4D4D4',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.alignof',
'keyword.operator.typeid',
'keyword.operator.alignas',
'keyword.operator.instanceof',
'keyword.operator.logical.python',
'keyword.operator.wordlike',
],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: ['punctuation.section.embedded.begin.php', 'punctuation.section.embedded.end.php'],
settings: {
foreground: '#569CD6',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#9CDCFE',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#B5CEA8',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#D4D4D4',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#569CD6',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#FFFFFF',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#6796E6',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#F44747',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#B267E6',
},
},
],
};
@@ -1,435 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ThemeRegistrationAny } from 'shiki';
export const vsLight: ThemeRegistrationAny = {
$schema: 'vscode://schemas/color-theme',
type: 'light',
colors: {
'actionBar.toggledBackground': '#dddddd',
'activityBarBadge.background': '#007acc',
'checkbox.border': '#919191',
'editor.background': '#ffffff',
'editor.foreground': '#000000',
'editor.inactiveSelectionBackground': '#e5ebf1',
'editor.selectionHighlightBackground': '#add6ff80',
'editorIndentGuide.activeBackground1': '#939393',
'editorIndentGuide.background1': '#d3d3d3',
'editorSuggestWidget.background': '#f3f3f3',
'input.placeholderForeground': '#767676',
'list.activeSelectionIconForeground': '#ffffff',
'list.focusAndSelectionOutline': '#90c2f9',
'list.hoverBackground': '#e8e8e8',
'menu.border': '#d4d4d4',
'notebook.cellBorderColor': '#e8e8e8',
'notebook.selectedCellBackground': '#c8ddf150',
'ports.iconRunningProcessForeground': '#369432',
'searchEditor.textInputBorder': '#cecece',
'settings.numberInputBorder': '#cecece',
'settings.textInputBorder': '#cecece',
'sideBarSectionHeader.background': '#00000000',
'sideBarSectionHeader.border': '#61616130',
'sideBarTitle.foreground': '#6f6f6f',
'statusBarItem.errorBackground': '#c72e0f',
'statusBarItem.remoteBackground': '#16825d',
'statusBarItem.remoteForeground': '#ffffff',
'tab.lastPinnedBorder': '#61616130',
'terminal.inactiveSelectionBackground': '#e5ebf1',
'widget.border': '#d4d4d4',
},
tokenColors: [
{
scope: [
'meta.embedded',
'source.groovy.embedded',
'string meta.image.inline.markdown',
'variable.legacy.builtin.python',
],
settings: {
foreground: '#000000',
},
},
{
scope: 'emphasis',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'strong',
settings: {
fontStyle: 'bold',
},
},
{
scope: 'meta.diff.header',
settings: {
foreground: '#000080',
},
},
{
scope: 'comment',
settings: {
foreground: '#008000',
},
},
{
scope: 'constant.language',
settings: {
foreground: '#0000FF',
},
},
{
scope: [
'constant.numeric',
'variable.other.enummember',
'keyword.operator.plus.exponent',
'keyword.operator.minus.exponent',
],
settings: {
foreground: '#098658',
},
},
{
scope: 'constant.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: 'entity.name.tag',
settings: {
foreground: '#800000',
},
},
{
scope: 'entity.name.selector',
settings: {
foreground: '#800000',
},
},
{
scope: 'entity.other.attribute-name',
settings: {
foreground: '#E50000',
},
},
{
scope: [
'entity.other.attribute-name.class.css',
'entity.other.attribute-name.class.mixin.css',
'entity.other.attribute-name.id.css',
'entity.other.attribute-name.parent-selector.css',
'entity.other.attribute-name.pseudo-class.css',
'entity.other.attribute-name.pseudo-element.css',
'source.css.less entity.other.attribute-name.id',
'entity.other.attribute-name.scss',
],
settings: {
foreground: '#800000',
},
},
{
scope: 'invalid',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'markup.underline',
settings: {
fontStyle: 'underline',
},
},
{
scope: 'markup.bold',
settings: {
foreground: '#000080',
fontStyle: 'bold',
},
},
{
scope: 'markup.heading',
settings: {
foreground: '#800000',
fontStyle: 'bold',
},
},
{
scope: 'markup.italic',
settings: {
fontStyle: 'italic',
},
},
{
scope: 'markup.strikethrough',
settings: {
fontStyle: 'strikethrough',
},
},
{
scope: 'markup.inserted',
settings: {
foreground: '#098658',
},
},
{
scope: 'markup.deleted',
settings: {
foreground: '#A31515',
},
},
{
scope: 'markup.changed',
settings: {
foreground: '#0451A5',
},
},
{
scope: ['punctuation.definition.quote.begin.markdown', 'punctuation.definition.list.begin.markdown'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'markup.inline.raw',
settings: {
foreground: '#800000',
},
},
{
scope: 'punctuation.definition.tag',
settings: {
foreground: '#800000',
},
},
{
scope: ['meta.preprocessor', 'entity.name.function.preprocessor'],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'meta.preprocessor.string',
settings: {
foreground: '#A31515',
},
},
{
scope: 'meta.preprocessor.numeric',
settings: {
foreground: '#098658',
},
},
{
scope: 'meta.structure.dictionary.key.python',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'storage',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'storage.type',
settings: {
foreground: '#0000FF',
},
},
{
scope: ['storage.modifier', 'keyword.operator.noexcept'],
settings: {
foreground: '#0000FF',
},
},
{
scope: ['string', 'meta.embedded.assembly'],
settings: {
foreground: '#A31515',
},
},
{
scope: [
'string.comment.buffered.block.pug',
'string.quoted.pug',
'string.interpolated.pug',
'string.unquoted.plain.in.yaml',
'string.unquoted.plain.out.yaml',
'string.unquoted.block.yaml',
'string.quoted.single.yaml',
'string.quoted.double.xml',
'string.quoted.single.xml',
'string.unquoted.cdata.xml',
'string.quoted.double.html',
'string.quoted.single.html',
'string.unquoted.html',
'string.quoted.single.handlebars',
'string.quoted.double.handlebars',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'string.regexp',
settings: {
foreground: '#811F3F',
},
},
{
scope: [
'punctuation.definition.template-expression.begin',
'punctuation.definition.template-expression.end',
'punctuation.section.embedded',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: ['meta.template.expression'],
settings: {
foreground: '#000000',
},
},
{
scope: [
'support.constant.property-value',
'support.constant.font-name',
'support.constant.media-type',
'support.constant.media',
'constant.other.color.rgb-value',
'constant.other.rgb-value',
'support.constant.color',
],
settings: {
foreground: '#0451A5',
},
},
{
scope: [
'support.type.vendored.property-name',
'support.type.property-name',
'variable.css',
'variable.scss',
'variable.other.less',
'source.coffee.embedded',
],
settings: {
foreground: '#E50000',
},
},
{
scope: ['support.type.property-name.json'],
settings: {
foreground: '#0451A5',
},
},
{
scope: 'keyword',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.control',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.operator',
settings: {
foreground: '#000000',
},
},
{
scope: [
'keyword.operator.new',
'keyword.operator.expression',
'keyword.operator.cast',
'keyword.operator.sizeof',
'keyword.operator.alignof',
'keyword.operator.typeid',
'keyword.operator.alignas',
'keyword.operator.instanceof',
'keyword.operator.logical.python',
'keyword.operator.wordlike',
],
settings: {
foreground: '#0000FF',
},
},
{
scope: 'keyword.other.unit',
settings: {
foreground: '#098658',
},
},
{
scope: ['punctuation.section.embedded.begin.php', 'punctuation.section.embedded.end.php'],
settings: {
foreground: '#800000',
},
},
{
scope: 'support.function.git-rebase',
settings: {
foreground: '#0451A5',
},
},
{
scope: 'constant.sha.git-rebase',
settings: {
foreground: '#098658',
},
},
{
scope: ['storage.modifier.import.java', 'variable.language.wildcard.java', 'storage.modifier.package.java'],
settings: {
foreground: '#000000',
},
},
{
scope: 'variable.language',
settings: {
foreground: '#0000FF',
},
},
{
scope: 'ref.matchtext',
settings: {
foreground: '#000000',
},
},
{
scope: 'token.info-token',
settings: {
foreground: '#316BCD',
},
},
{
scope: 'token.warn-token',
settings: {
foreground: '#CD9731',
},
},
{
scope: 'token.error-token',
settings: {
foreground: '#CD3131',
},
},
{
scope: 'token.debug-token',
settings: {
foreground: '#800080',
},
},
],
};
@@ -1,17 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
export function pluralize(count: number, noun: string, suffix = 's') {
return `${count} ${noun}${count !== 1 ? suffix : ''}`;
}
@@ -1,134 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { commands, Disposable, languages, LanguageStatusItem, LanguageStatusSeverity, window, workspace } from 'vscode';
import { IDisposable } from '../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { CopilotConfigPrefix } from '../../lib/src/constants';
import { CMDQuotaExceeded } from '../../lib/src/openai/fetch';
import { StatusChangedEvent, StatusReporter } from '../../lib/src/progress';
import { isCompletionEnabled, isInlineSuggestEnabled } from './config';
import { CMDToggleStatusMenuChat } from './constants';
import { ICompletionsExtensionStatus } from './extensionStatus';
import { Icon } from './icon';
export class CopilotStatusBar extends StatusReporter implements IDisposable {
readonly item!: LanguageStatusItem;
showingMessage = false;
private disposables: Disposable[] = [];
constructor(
id: string,
@ICompletionsExtensionStatus readonly extensionStatusService: ICompletionsExtensionStatus,
@IInstantiationService readonly instantiationService: IInstantiationService,
) {
super();
this.item = languages.createLanguageStatusItem(id, '*');
this.disposables.push(this.item);
this.updateStatusBarIndicator();
this.disposables.push(
window.onDidChangeActiveTextEditor(() => {
this.updateStatusBarIndicator();
})
);
this.disposables.push(
workspace.onDidCloseTextDocument(() => {
this.updateStatusBarIndicator();
})
);
this.disposables.push(
workspace.onDidOpenTextDocument(() => {
this.updateStatusBarIndicator();
})
);
this.disposables.push(
workspace.onDidChangeConfiguration(e => {
if (!e.affectsConfiguration(CopilotConfigPrefix)) { return; }
this.updateStatusBarIndicator();
})
);
}
override didChange(event: StatusChangedEvent): void {
this.extensionStatusService.kind = event.kind;
this.extensionStatusService.message = event.message;
this.extensionStatusService.command = event.command;
this.updateStatusBarIndicator();
}
private checkEnabledForLanguage(): boolean {
return this.instantiationService.invokeFunction(isCompletionEnabled) ?? true;
}
protected updateStatusBarIndicator() {
if (this.isDisposed()) {
return;
}
void commands.executeCommand(
'setContext',
'github.copilot.completions.quotaExceeded',
this.extensionStatusService.command?.command === CMDQuotaExceeded
);
const enabled = this.checkEnabledForLanguage();
void commands.executeCommand('setContext', 'github.copilot.completions.enabled', enabled);
this.item.command = { command: CMDToggleStatusMenuChat, title: 'View Details' };
switch (this.extensionStatusService.kind) {
case 'Error':
this.item.severity = LanguageStatusSeverity.Error;
this.item.text = `${Icon.Warning} Completions`;
this.item.detail = 'Error';
break;
case 'Warning':
this.item.severity = LanguageStatusSeverity.Warning;
this.item.text = `${Icon.Warning} Completions`;
this.item.detail = 'Temporary issues';
break;
case 'Inactive':
this.item.severity = LanguageStatusSeverity.Information;
this.item.text = `${Icon.Blocked} Completions`;
this.item.detail = 'Inactive';
break;
case 'Normal':
this.item.severity = LanguageStatusSeverity.Information;
if (!isInlineSuggestEnabled()) {
this.item.text = `${Icon.NotConnected} Completions`;
this.item.detail = 'VS Code inline suggestions disabled';
} else if (!enabled) {
this.item.text = `${Icon.NotConnected} Completions`;
this.item.detail = 'Disabled';
} else {
this.item.text = `${Icon.Logo} Completions`;
this.item.detail = '';
}
this.item.command.title = 'Open Menu';
break;
}
this.item.accessibilityInformation = {
label: 'Inline Suggestions',
};
if (this.extensionStatusService.command) {
this.item.command = this.extensionStatusService.command;
this.item.detail = this.extensionStatusService.message;
}
}
dispose() {
for (const d of this.disposables) {
d.dispose();
}
this.disposables = [];
}
private isDisposed() {
return this.disposables.length === 0;
}
}
@@ -1,169 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { QuickPick, QuickPickItem, QuickPickItemKind, commands, l10n, window } from 'vscode';
import { isWeb } from '../../../../../util/vs/base/common/platform';
import { IInstantiationService } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { isCompletionEnabled, isInlineSuggestEnabled } from './config';
import { CMDCollectDiagnosticsChat, CMDDisableCompletionsChat, CMDEnableCompletionsChat, CMDOpenDocumentationClient, CMDOpenLogsClient, CMDOpenModelPickerClient, CMDOpenPanelClient } from './constants';
import { ICompletionsExtensionStatus } from './extensionStatus';
import { Icon } from './icon';
export class CopilotStatusBarPickMenu {
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICompletionsExtensionStatus private readonly extensionStatusService: ICompletionsExtensionStatus,
) { }
showStatusMenu() {
const quickpickList = window.createQuickPick();
quickpickList.placeholder = l10n.t('Select an option');
quickpickList.title = l10n.t('Configure Inline Suggestions');
quickpickList.items = this.collectQuickPickItems();
quickpickList.onDidAccept(() => this.handleItemSelection(quickpickList));
quickpickList.show();
return quickpickList;
}
async handleItemSelection(quickpickList: QuickPick<QuickPickItem>): Promise<void> {
const selection = quickpickList.selectedItems[0];
if (selection === undefined) { return; }
if ('command' in selection) {
const commandSelection = selection as CommandQuickItem;
await commands.executeCommand(commandSelection.command, ...commandSelection.commandArgs);
quickpickList.hide();
} else {
throw new Error('Unexpected Copilot quick picker selection');
}
}
private collectQuickPickItems() {
return [
this.newStatusItem(),
this.newSeparator(),
...this.collectLanguageSpecificItems(),
this.newKeyboardItem(),
this.newSettingsItem(),
...this.collectDiagnosticsItems(),
this.newOpenLogsItem(),
this.newSeparator(),
this.newDocsItem(),
//this.newForumItem(),
];
}
private collectLanguageSpecificItems() {
const items: QuickPickItem[] = [];
if (!this.hasActiveStatus()) { return items; }
const editor = window.activeTextEditor;
if (!isWeb && editor) { items.push(this.newPanelItem()); }
// Always show the model picker even if only one model is available
if (!isWeb) { items.push(this.newChangeModelItem()); }
if (editor) { items.push(...this.newEnableLanguageItem()); }
if (items.length) { items.push(this.newSeparator()); }
return items;
}
private hasActiveStatus() {
return ['Normal'].includes(this.extensionStatusService.kind);
}
private isCompletionEnabled() {
return isInlineSuggestEnabled() && this.instantiationService.invokeFunction(isCompletionEnabled);
}
private newEnableLanguageItem() {
const isEnabled = this.isCompletionEnabled();
if (isEnabled) {
return [this.newCommandItem(l10n.t('Disable Inline Suggestions'), CMDDisableCompletionsChat)];
} else if (isEnabled === false) {
return [this.newCommandItem(l10n.t('Enable Inline Suggestions'), CMDEnableCompletionsChat)];
} else {
return [];
}
}
private newStatusItem() {
let statusText;
let statusIcon = Icon.Logo;
switch (this.extensionStatusService.kind) {
case 'Normal':
statusText = l10n.t('Ready');
if (isInlineSuggestEnabled() === false) {
statusText += ` (${l10n.t('VS Code inline suggestions disabled')})`;
} else if (this.instantiationService.invokeFunction(isCompletionEnabled) === false) {
statusText += ` (${l10n.t('Disabled')})`;
}
break;
case 'Inactive':
statusText = this.extensionStatusService.message || l10n.t('Copilot is currently inactive');
statusIcon = Icon.Blocked;
break;
default:
statusText = this.extensionStatusService.message || l10n.t('Copilot has encountered an error');
statusIcon = Icon.NotConnected;
break;
}
return this.newCommandItem(`${statusIcon} ${l10n.t('Status')}: ${statusText}`, CMDOpenLogsClient);
}
private newOpenLogsItem() {
return this.newCommandItem(l10n.t('Open Logs...'), CMDOpenLogsClient);
}
private collectDiagnosticsItems() {
if (isWeb) { return []; }
return [this.newCommandItem(l10n.t('Show Diagnostics...'), CMDCollectDiagnosticsChat)];
}
private newKeyboardItem() {
return this.newCommandItem(l10n.t('$(keyboard) Edit Keyboard Shortcuts...'), 'workbench.action.openGlobalKeybindings', [
'copilot',
]);
}
private newSettingsItem() {
return this.newCommandItem(l10n.t('$(settings-gear) Edit Settings...'), 'workbench.action.openSettings', [
'GitHub Copilot',
]);
}
private newPanelItem() {
return this.newCommandItem(l10n.t('Open Completions Panel...'), CMDOpenPanelClient);
}
private newChangeModelItem() {
return this.newCommandItem(l10n.t('Change Completions Model...'), CMDOpenModelPickerClient);
}
private newDocsItem() {
return this.newCommandItem(
l10n.t('$(remote-explorer-documentation) View Copilot Documentation...'),
CMDOpenDocumentationClient
);
}
private newCommandItem(label: string, command: string, commandArgs?: string[]): CommandQuickItem {
return new CommandQuickItem(label, command, commandArgs || []);
}
private newSeparator(): QuickPickItem {
return {
label: '',
kind: QuickPickItemKind.Separator,
};
}
}
class CommandQuickItem implements QuickPickItem {
constructor(
readonly label: string,
readonly command: string,
readonly commandArgs: string[]
) { }
}
@@ -1,45 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { commands, Disposable } from 'vscode';
import { IDisposable } from '../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService, type ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { handleException } from '../../lib/src/defaultHandlers';
import { Logger } from '../../lib/src/logger';
function exception(accessor: ServicesAccessor, error: unknown, origin: string, logger?: Logger) {
if (error instanceof Error && error.name === 'Canceled') {
// these are VS Code cancellations
return;
}
if (error instanceof Error && error.name === 'CodeExpectedError') {
// expected errors from VS Code
return;
}
handleException(accessor, error, origin, logger);
}
export function registerCommand(accessor: ServicesAccessor, command: string, fn: (...args: unknown[]) => unknown): Disposable {
const instantiationService = accessor.get(IInstantiationService);
try {
const disposable = commands.registerCommand(command, async (...args: unknown[]) => {
try {
await fn(...args);
} catch (error) {
// Pass in the command string as the origin
instantiationService.invokeFunction(exception, error, command);
}
});
return disposable;
} catch (error) {
console.error(`Error registering command ${command}:`, error);
throw error;
}
}
// Wrapper that handles errors and cleans up the command on extension deactivation
export function registerCommandWrapper(accessor: ServicesAccessor, command: string, fn: (...args: unknown[]) => unknown): IDisposable {
return registerCommand(accessor, command, fn);
}
@@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ConfigKey, ConfigKeyType, DefaultsOnlyConfigProvider, InMemoryConfigProvider } from '../../../lib/src/config';
import { VSCodeConfigProvider } from '../config';
/**
* Provides the default configurations, except lets through the configured value
* of test-only settings like the proxy override URL.
*/
export class ExtensionTestConfigProvider extends InMemoryConfigProvider {
private readonly vscConfigProvider = new VSCodeConfigProvider();
constructor() {
super(new DefaultsOnlyConfigProvider());
}
override getConfig<T>(key: ConfigKeyType): T {
if (key === ConfigKey.DebugTestOverrideProxyUrl) {
return this.vscConfigProvider.getConfig<T>(key);
}
return super.getConfig(key);
}
}
@@ -1,34 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SyncDescriptor } from '../../../../../../util/vs/platform/instantiation/common/descriptors';
import { createExtensionTestingServices } from '../../../../../test/vscode-node/services';
import { ICompletionsEditorAndPluginInfo } from '../../../lib/src/config';
import { ICompletionsFileSystemService } from '../../../lib/src/fileSystem';
import { ICompletionsFetcherService } from '../../../lib/src/networking';
import { _createBaselineContext } from '../../../lib/src/test/context';
import { StaticFetcher } from '../../../lib/src/test/fetcher';
import { ICompletionsTextDocumentManagerService } from '../../../lib/src/textDocumentManager';
import { VSCodeEditorInfo } from '../config';
import { CopilotExtensionStatus, ICompletionsExtensionStatus } from '../extensionStatus';
import { extensionFileSystem } from '../fileSystem';
import { ExtensionTextDocumentManager } from '../textDocumentManager';
import { ExtensionTestConfigProvider } from './config';
/**
* A default context for VSCode extension testing, building on general one in `lib`.
* Only includes items that are needed for almost all extension tests.
*/
export function createExtensionTestingContext() {
let serviceCollection = createExtensionTestingServices();
serviceCollection = _createBaselineContext(serviceCollection, new ExtensionTestConfigProvider());
serviceCollection.define(ICompletionsFetcherService, new StaticFetcher());
serviceCollection.define(ICompletionsEditorAndPluginInfo, new VSCodeEditorInfo());
serviceCollection.define(ICompletionsTextDocumentManagerService, new SyncDescriptor(ExtensionTextDocumentManager));
serviceCollection.define(ICompletionsFileSystemService, extensionFileSystem);
serviceCollection.define(ICompletionsExtensionStatus, new CopilotExtensionStatus());
return serviceCollection;
}
@@ -1,113 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import assert from 'assert';
import sinon from 'sinon';
import { commands, env } from 'vscode';
import { SyncDescriptor } from '../../../../../../util/vs/platform/instantiation/common/descriptors';
import { IInstantiationService, ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { AvailableModelsManager, ICompletionsModelManagerService } from '../../../lib/src/openai/model';
import { ModelPickerManager } from './../modelPicker';
import { createExtensionTestingContext } from './context';
suite('ModelPickerManager unit tests', function () {
let accessor: ServicesAccessor;
let modelPicker: ModelPickerManager;
let availableModelsManager: ICompletionsModelManagerService;
let sandbox: sinon.SinonSandbox;
// Couple of fake models to use in our tests.
const fakeModels = [
{
modelId: 'model-a',
label: 'Model A',
type: 'model',
alwaysShow: true,
preview: false,
tokenizer: 'o200k_base',
},
{
modelId: 'model-b',
label: 'Model B',
type: 'model',
alwaysShow: true,
preview: false,
tokenizer: 'cl100k_base',
},
];
setup(function () {
sandbox = sinon.createSandbox();
// Create our test context, and stub the AvailableModelsManager to return our fake models.
const serviceCollection = createExtensionTestingContext();
serviceCollection.define(ICompletionsModelManagerService, new SyncDescriptor(AvailableModelsManager, [true]));
accessor = serviceCollection.createTestingAccessor();
availableModelsManager = accessor.get(ICompletionsModelManagerService);
sandbox.stub(availableModelsManager, 'getGenericCompletionModels').returns(fakeModels);
modelPicker = accessor.get(IInstantiationService).createInstance(ModelPickerManager);
});
teardown(async function () {
// Make sure to close any open quick pick dialogs after each test.
await commands.executeCommand('workbench.action.closeQuickOpen');
sandbox.restore();
});
test('showModelPicker returns correct items', function () {
const instantiationService = accessor.get(IInstantiationService);
modelPicker = instantiationService.createInstance(ModelPickerManager);
const quickPick = modelPicker.showModelPicker();
// Check that we have the correct number of items
// The items should include the two fake models, a separator, and a learn more item.
assert(quickPick.items.length === 4, quickPick.items.length.toString());
assert.strictEqual(quickPick.items[0].modelId, 'model-a');
assert.strictEqual(quickPick.items[1].modelId, 'model-b');
assert.strictEqual(quickPick.items[2].type, 'separator');
assert.strictEqual(quickPick.items[3].type, 'learn-more');
});
test('selecting a model updates user selection', async function () {
// Stub out setting model
const setModelStub = sandbox.stub(modelPicker, 'setUserSelectedCompletionModel').resolves();
const quickPick = modelPicker.showModelPicker();
const secondItem = quickPick.items[1];
assert(secondItem !== undefined, 'model picker should have a model-b second item.');
// Fake selecting the second item
quickPick.activeItems = [secondItem];
await modelPicker.handleModelSelection(quickPick);
// Test that we updated the user configuration with the selected model
assert(setModelStub.calledOnce, 'setUserSelectedCompletionModel should be called once');
assert.strictEqual(setModelStub.firstCall.args[0], secondItem.modelId);
});
test('selecting the learn more link tries to open the learn more url', async function () {
// Stub openExternal
const openUrlStub = sandbox.stub(env, 'openExternal').resolves();
const quickPick = modelPicker.showModelPicker();
const learnMoreItem = quickPick.items[3];
assert(learnMoreItem !== undefined, 'model picker should have a learn more item.');
// Fake selecting the learn more item
quickPick.activeItems = [learnMoreItem];
await modelPicker.handleModelSelection(quickPick);
// Test that we opened the learn more URL
assert(openUrlStub.calledOnce, 'openUrl should be called once');
assert.strictEqual(
openUrlStub.firstCall.args[0].toString(),
'https://aka.ms/CopilotCompletionsModelPickerLearnMore'
);
});
});
@@ -1,123 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { window, workspace } from 'vscode';
import { detectLanguage } from '../../lib/src/language/languageDetection';
import { CopilotTextDocument, INotebookCell, INotebookDocument, ITextDocument } from '../../lib/src/textDocument';
import { TextDocumentManager, WorkspaceFoldersChangeEvent } from '../../lib/src/textDocumentManager';
import { transformEvent } from '../../lib/src/util/event';
import { normalizeUri } from '../../lib/src/util/uri';
// List of document URI schemes that avoid ghost text suggestions
const ignoreUriSchemes = new Set([
'output', // vscode output pane (important: avoids infinite log loop)
'search-editor', // search results virtual document
'comment', // very little context available and suggestions are often bad
'git', // virtual file tracked by git
'chat-editing-snapshot-text-model', // VS Code Chat temporary editing snapshot
]);
export function wrapDoc(doc: vscode.TextDocument): ITextDocument | undefined {
if (ignoreUriSchemes.has(doc.uri.scheme)) {
return;
}
let text: string;
try {
text = doc.getText();
} catch (e) {
// "Invalid string length", it's too big to fit in a string
if (e instanceof RangeError) {
return;
}
throw e;
}
const languageId = detectLanguage({ uri: doc.uri.toString(), languageId: doc.languageId });
return CopilotTextDocument.create(doc.uri.toString(), doc.languageId, doc.version, text, languageId);
}
export class ExtensionTextDocumentManager extends TextDocumentManager {
override onDidFocusTextDocument = transformEvent(window.onDidChangeActiveTextEditor, event => {
return { document: event && { uri: event.document.uri.toString() } };
});
override onDidChangeTextDocument = transformEvent(workspace.onDidChangeTextDocument, e => {
const document = wrapDoc(e.document);
return document && { document, contentChanges: e.contentChanges };
});
override onDidOpenTextDocument = transformEvent(workspace.onDidOpenTextDocument, e => {
// use wrapDoc() to handle the "Invalid string length" case
const text = wrapDoc(e)?.getText();
if (text === undefined) {
return;
}
return { document: { uri: e.uri.toString(), languageId: e.languageId, version: e.version, text } };
});
override onDidCloseTextDocument = transformEvent(workspace.onDidCloseTextDocument, e => {
return { document: { uri: normalizeUri(e.uri.toString()) } };
});
override onDidChangeWorkspaceFolders = transformEvent(
workspace.onDidChangeWorkspaceFolders,
(e): WorkspaceFoldersChangeEvent => {
return {
workspaceFolders: this.getWorkspaceFolders(),
added: e.added.map(f => ({ uri: f.uri.toString(), name: f.name })),
removed: e.removed.map(f => ({ uri: f.uri.toString(), name: f.name })),
};
}
);
getTextDocumentsUnsafe(): ITextDocument[] {
const docs: ITextDocument[] = [];
for (const vscodeDoc of workspace.textDocuments) {
const doc = wrapDoc(vscodeDoc);
if (doc) {
docs.push(doc);
}
}
return docs;
}
findNotebook(doc: { uri: string }): INotebookDocument | undefined {
for (const notebook of workspace.notebookDocuments) {
if (notebook.getCells().some(cell => cell.document.uri.toString() === doc.uri.toString())) {
return {
getCells: () => notebook.getCells().map(cell => this.wrapCell(cell)),
getCellFor: ({ uri }: { uri: string }) => {
const cell = notebook.getCells().find(cell => cell.document.uri.toString() === uri.toString());
return cell ? this.wrapCell(cell) : undefined;
},
};
}
}
}
wrapCell(cell: vscode.NotebookCell): INotebookCell {
return {
...cell,
get document(): ITextDocument {
return CopilotTextDocument.create(
cell.document.uri.toString(),
cell.document.languageId,
cell.document.version,
cell.document.getText(),
// use the original language id as cells have no metadata to leverage for language detection
cell.document.languageId
);
},
};
}
getWorkspaceFolders() {
return (
workspace.workspaceFolders?.map(f => {
return { uri: f.uri.toString(), name: f.name };
}) ?? []
);
}
}
@@ -1,210 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
CancellationToken,
InlineCompletionContext,
InlineCompletionEndOfLifeReason,
InlineCompletionItemProvider,
InlineCompletionList,
InlineCompletionTriggerKind,
PartialAcceptInfo,
Position,
TextDocument,
workspace
} from 'vscode';
import { Disposable } from '../../../../../util/vs/base/common/lifecycle';
import { LineEdit } from '../../../../../util/vs/editor/common/core/edits/lineEdit';
import { TextEdit, TextReplacement } from '../../../../../util/vs/editor/common/core/edits/textEdit';
import { Range } from '../../../../../util/vs/editor/common/core/range';
import { LineBasedText } from '../../../../../util/vs/editor/common/core/text/abstractText';
import { IInstantiationService, ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { InlineEditLogger } from '../../../../inlineEdits/vscode-node/parts/inlineEditLogger';
import { GhostTextContext } from '../../../common/ghostTextContext';
import { ICompletionsTelemetryService } from '../../bridge/src/completionsTelemetryServiceBridge';
import { BuildInfo } from '../../lib/src/config';
import { CopilotConfigPrefix } from '../../lib/src/constants';
import { handleException } from '../../lib/src/defaultHandlers';
import { Logger } from '../../lib/src/logger';
import { isCompletionEnabledForDocument } from './config';
import { CopilotCompletionFeedbackTracker, sendCompletionFeedbackCommand } from './copilotCompletionFeedbackTracker';
import { ICompletionsExtensionStatus } from './extensionStatus';
import { GhostTextCompletionItem, GhostTextCompletionList, GhostTextProvider } from './ghostText/ghostTextProvider';
const logger = new Logger('inlineCompletionItemProvider');
function quickSuggestionsDisabled() {
const qs = workspace.getConfiguration('editor.quickSuggestions');
return qs.get('other') !== 'on' && qs.get('comments') !== 'on' && qs.get('strings') !== 'on';
}
export function exception(accessor: ServicesAccessor, error: unknown, origin: string, logger?: Logger) {
if (error instanceof Error && error.name === 'Canceled') {
// these are VS Code cancellations
return;
}
if (error instanceof Error && error.name === 'CodeExpectedError') {
// expected errors from VS Code
return;
}
const telemetryService = accessor.get(ICompletionsTelemetryService);
telemetryService.sendGHTelemetryException(error, 'codeUnification.completions.exception');
handleException(accessor, error, origin, logger);
}
/** @public */
export class CopilotInlineCompletionItemProvider extends Disposable implements InlineCompletionItemProvider {
private readonly copilotCompletionFeedbackTracker: CopilotCompletionFeedbackTracker;
private readonly ghostTextProvider: GhostTextProvider;
private readonly inlineEditLogger: InlineEditLogger;
public onDidChange = undefined;
public handleListEndOfLifetime: InlineCompletionItemProvider['handleListEndOfLifetime'] = undefined;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICompletionsTelemetryService private readonly telemetryService: ICompletionsTelemetryService,
@ICompletionsExtensionStatus private readonly extensionStatusService: ICompletionsExtensionStatus,
) {
super();
this.copilotCompletionFeedbackTracker = this._register(this.instantiationService.createInstance(CopilotCompletionFeedbackTracker));
this.ghostTextProvider = this.instantiationService.createInstance(GhostTextProvider);
this.inlineEditLogger = this.instantiationService.createInstance(InlineEditLogger);
}
async provideInlineCompletionItems(
doc: TextDocument,
position: Position,
context: InlineCompletionContext,
token: CancellationToken
): Promise<GhostTextCompletionList | undefined> {
const logContext = new GhostTextContext(doc.uri.toString(), doc.version, context);
try {
return await this._provideInlineCompletionItems(doc, position, context, logContext, token);
} catch (e) {
logContext.setError(e);
this.telemetryService.sendGHTelemetryException(e, 'codeUnification.completions.exception');
} finally {
this.inlineEditLogger.add(logContext);
}
}
private async _provideInlineCompletionItems(
doc: TextDocument,
position: Position,
context: InlineCompletionContext,
logContext: GhostTextContext,
token: CancellationToken
): Promise<GhostTextCompletionList | undefined> {
if (context.triggerKind === InlineCompletionTriggerKind.Automatic) {
if (!this.instantiationService.invokeFunction(isCompletionEnabledForDocument, doc)) {
return;
}
if (this.extensionStatusService.kind === 'Error') {
return;
}
}
const copilotConfig = workspace.getConfiguration(CopilotConfigPrefix);
// Constraining the generated inline completion to match selectedCompletionInfo sandbags Copilot pretty hard, as
// typically it's just the first entry in the list alphabetically. But if we generate a result that doesn't
// match it, VS Code won't show it to the user unless the completion dropdown is dismissed. Historically we've
// chosen to favor completion quality, but this option allows opting into or out of generating a completion that
// VS Code will actually show.
if (!copilotConfig.get('respectSelectedCompletionInfo', quickSuggestionsDisabled() || BuildInfo.isPreRelease())) {
context = { ...context, selectedCompletionInfo: undefined };
}
try {
let items = await this.ghostTextProvider.provideInlineCompletionItems(doc, position, context, token);
if (!items) {
if (token.isCancellationRequested) {
logContext.setIsSkipped();
}
return undefined;
}
// If the language client provides a list of items, we want to add the send feedback command to it.
if (Array.isArray(items)) {
items = { items };
}
this.logSuggestion(logContext, doc, items);
return {
...items,
commands: [sendCompletionFeedbackCommand],
};
} catch (e) {
this.instantiationService.invokeFunction(exception, e, '._provideInlineCompletionItems', logger);
logContext.setError(e);
}
}
handleDidShowCompletionItem(item: GhostTextCompletionItem) {
try {
this.copilotCompletionFeedbackTracker.trackItem(item);
return this.ghostTextProvider.handleDidShowCompletionItem(item);
} catch (e) {
this.instantiationService.invokeFunction(exception, e, '.handleDidShowCompletionItem', logger);
}
}
handleDidPartiallyAcceptCompletionItem(
item: GhostTextCompletionItem,
acceptedLengthOrInfo: number | PartialAcceptInfo
) {
try {
return this.ghostTextProvider.handleDidPartiallyAcceptCompletionItem(item, acceptedLengthOrInfo);
} catch (e) {
this.instantiationService.invokeFunction(exception, e, '.handleDidPartiallyAcceptCompletionItem', logger);
}
}
handleEndOfLifetime(completionItem: GhostTextCompletionItem, reason: InlineCompletionEndOfLifeReason) {
try {
return this.ghostTextProvider.handleEndOfLifetime(completionItem, reason);
} catch (e) {
this.instantiationService.invokeFunction(exception, e, '.handleEndOfLifetime', logger);
}
}
private logSuggestion(
logContext: GhostTextContext,
doc: TextDocument,
items: InlineCompletionList
) {
if (items.items.length === 0) {
logContext.markAsNoSuggestions();
logContext.addLog('No inline completion items provided');
return;
}
const firstItem = items.items[0];
if (!firstItem.range) {
logContext.addLog('Inline completion item has no range');
return;
}
if (typeof firstItem.insertText !== 'string') {
logContext.addLog('Inline completion item has non-string insertText');
return;
}
const text = new LineBasedText(lineNumber => doc.lineAt(lineNumber - 1).text, doc.lineCount);
const lineEdit = LineEdit.fromTextEdit(
new TextEdit(
[new TextReplacement(
new Range(firstItem.range.start.line + 1, firstItem.range.start.character + 1, firstItem.range.end.line + 1, firstItem.range.end.character + 1),
firstItem.insertText,
)],
),
text
);
const patch = lineEdit.humanReadablePatch(text.getLines());
logContext.setResult(patch);
}
}
@@ -1,75 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
require('tsx/cjs');
const { globSync } = require('glob');
const Mocha = require('mocha');
const path = require('path');
const dotenv = require('dotenv');
const envfile = path.join(__dirname, '../../../../../../.env');
dotenv.config({ path: envfile });
function run() {
const projectRoot = path.resolve(__dirname, '../..');
const mochaOptions = {
ui: 'tdd',
color: !process.env.NO_COLOR && process.env.TERM !== 'dumb',
reporter: 'mocha-multi-reporters',
reporterOptions: {
reporterEnabled: 'spec',
},
};
if (process.env.MOCHA_GREP) {
mochaOptions.grep = process.env.MOCHA_GREP;
}
if (process.env.CI) {
mochaOptions.forbidOnly = true;
mochaOptions.retries = 2;
mochaOptions.reporterOptions.reporterEnabled += ', mocha-junit-reporter';
mochaOptions.reporterOptions.mochaJunitReporterReporterOptions = {
testCaseSwitchClassnameAndName: true,
testsuitesTitle: 'Copilot VS Code Extension Tests',
mochaFile: path.resolve(projectRoot, 'test-results-Extension.xml'),
};
}
if (process.env.GITHUB_EVENT_NAME === 'merge_group') {
mochaOptions.retries = 3;
}
// Create the mocha test
const mocha = new Mocha(mochaOptions);
let fileCount = 0;
(process.env.MOCHA_FILES || [
path.resolve(projectRoot, 'lib/src/**/*.test.{ts,tsx}'),
path.resolve(projectRoot, 'extension/src/**/*.test.{ts,tsx}')
].join('\n')).split('\n').forEach(f => {
globSync(f, { windowsPathsNoEscape: true }).forEach(f => {
fileCount++;
mocha.addFile(f);
});
});
if (!fileCount) {
throw new Error('No tests to run');
}
return new Promise((c, e) => {
try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
e(err);
}
});
}
module.exports = { run };
@@ -1,79 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { promises as fs } from 'fs';
import * as os from 'os';
import * as path from 'path';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { runTests } from '@vscode/test-electron';
async function main() {
const tempdir = await fs.mkdtemp(os.tmpdir() + '/copilot-extension-test-');
let exitCode;
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../..');
// The path to the extension test script (must be javascript)
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './run');
const launchArgs = [];
// Disable other extensions while testing,
launchArgs.push('--disable-extensions');
// use a temporary folder so we can run multiple instances of the same VS Code together
// see https://github.com/microsoft/vscode/issues/137678
launchArgs.push('--user-data-dir', tempdir);
const argv = await yargs(hideBin(process.argv))
.options({
stable: {
type: 'boolean',
default: false,
},
grep: {
alias: 'g',
type: 'string',
default: '',
},
})
.parse();
const version = argv.stable ? 'stable' : 'insiders';
const extensionTestsEnv: typeof process.env = {};
// Pass arguments to mocha by environment variables
if (argv.grep) { extensionTestsEnv.MOCHA_GREP = argv.grep; }
if (argv._.length > 0) { extensionTestsEnv.MOCHA_FILES = argv._.join('\n'); }
if (!process.stdout.isTTY) { extensionTestsEnv.NO_COLOR = 'true'; }
const workspaceFolder = await fs.mkdtemp(path.join(os.tmpdir(), 'copilot-extension-test-'));
launchArgs.push(workspaceFolder);
extensionTestsEnv.CORETEST = 'true';
//@dbaeumer This can be removed as soon as we have the cache handle CORETEST
extensionTestsEnv.VITEST = 'true';
// Download VS Code, unzip it and run the integration test
exitCode = await runTests({
version,
extensionDevelopmentPath,
extensionTestsPath,
launchArgs,
extensionTestsEnv,
});
} catch (err) {
console.error('Failed to run tests', err);
exitCode = 1;
} finally {
await fs.rm(tempdir, { recursive: true });
}
process.exit(exitCode);
}
void main();
@@ -1,72 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { CopilotToken } from '../../../../../../platform/authentication/common/copilotToken';
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { ThrottledDelayer } from '../../../../../../util/vs/base/common/async';
import { Disposable } from '../../../../../../util/vs/base/common/lifecycle';
export { CopilotToken } from '../../../../../../platform/authentication/common/copilotToken';
export const ICompletionsCopilotTokenManager = createServiceIdentifier<ICompletionsCopilotTokenManager>('ICompletionsCopilotTokenManager');
export interface ICompletionsCopilotTokenManager {
readonly _serviceBrand: undefined;
get token(): CopilotToken | undefined;
primeToken(): Promise<boolean>;
getToken(): Promise<CopilotToken>;
resetToken(httpError?: number): void;
getLastToken(): Omit<CopilotToken, 'token'> | undefined;
}
export class CopilotTokenManagerImpl extends Disposable implements ICompletionsCopilotTokenManager {
declare _serviceBrand: undefined;
private tokenRefetcher = new ThrottledDelayer(5_000);
private _token: CopilotToken | undefined;
get token() {
void this.tokenRefetcher.trigger(() => this.updateCachedToken());
return this._token;
}
constructor(
protected primed = false,
@IAuthenticationService private readonly authenticationService: IAuthenticationService
) {
super();
this.updateCachedToken();
this._register(this.authenticationService.onDidAuthenticationChange(() => this.updateCachedToken()));
}
/**
* Ensure we have a token and that the `StatusReporter` is up to date.
*/
primeToken(): Promise<boolean> {
try {
return this.getToken().then(
() => true,
() => false
);
} catch (e) {
return Promise.resolve(false);
}
}
async getToken(): Promise<CopilotToken> {
return this.updateCachedToken();
}
private async updateCachedToken(): Promise<CopilotToken> {
this._token = await this.authenticationService.getCopilotToken();
return this._token;
}
resetToken(httpError?: number): void {
this.authenticationService.resetCopilotToken();
}
getLastToken(): Omit<CopilotToken, 'token'> | undefined {
return this.authenticationService.copilotToken;
}
}
@@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { CopilotToken } from '../../../../../../platform/authentication/common/copilotToken';
export function onCopilotToken(authService: IAuthenticationService, listener: (token: Omit<CopilotToken, 'token'>) => unknown) {
return authService.onDidAuthenticationChange(() => {
const copilotToken = authService.copilotToken;
if (copilotToken) {
listener(copilotToken);
}
});
}
@@ -1,27 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CopilotToken } from './copilotTokenManager';
/**
* A function used to determine if the org list contains an known organization
* @param orgs The list of organizations the user is a member of
* @returns The first known organization or undefined if none are known.
*/
function findKnownOrg(orgs: string[]): string | undefined {
// Do not add org mapping
const known_orgs = [
'a5db0bcaae94032fe715fb34a5e4bce2',
'7184f66dfcee98cb5f08a1cb936d5225',
'faef89d9169d5eacf1d8c8dde3412e37',
'4535c7beffc844b46bb1ed4aa04d759a',
];
return known_orgs.find(o => orgs.includes(o));
}
export function getUserKind(token: Omit<CopilotToken, 'token'>): string {
const orgs = token.organizationList ?? [];
return findKnownOrg(orgs) ?? '';
}
@@ -1,54 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from '../../types/src';
import { ICompletionsTextDocumentManagerService } from './textDocumentManager';
/**
* A tracker which can take an arbitrary number of actions to run after a given timeout
* When all pushed timeouts have been resolved, the tracker disposes of itself.
*/
export class ChangeTracker {
private _offset: number;
get offset(): number {
return this._offset;
}
private _referenceCount = 0;
private _tracker: Disposable;
private _isDisposed = false;
constructor(
fileURI: string,
insertionOffset: number,
@ICompletionsTextDocumentManagerService documentManager: ICompletionsTextDocumentManagerService
) {
this._offset = insertionOffset;
this._tracker = documentManager.onDidChangeTextDocument(e => {
if (e.document.uri === fileURI) {
for (const cc of e.contentChanges) {
if (cc.rangeOffset + cc.rangeLength <= this.offset) {
const delta = cc.text.length - cc.rangeLength;
this._offset = this._offset + delta;
}
}
}
});
}
push(action: () => void, timeout: number): void {
if (this._isDisposed) {
throw new Error('Unable to push new actions to a disposed ChangeTracker');
}
this._referenceCount++;
setTimeout(() => {
action();
this._referenceCount--;
if (this._referenceCount === 0) {
this._tracker.dispose();
this._isDisposed = true;
}
}, timeout);
}
}
@@ -1,40 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../util/common/services';
import { Disposable, IDisposable } from '../../../../../util/vs/base/common/lifecycle';
import { IRange } from './textDocument';
export interface IPCitationDetail {
license: string;
url: string;
}
export interface IPDocumentCitation {
inDocumentUri: string;
offsetStart: number;
offsetEnd: number;
version?: number;
location?: IRange;
matchingText?: string;
details: IPCitationDetail[];
}
export const ICompletionsCitationManager = createServiceIdentifier<ICompletionsCitationManager>('ICompletionsCitationManager');
export interface ICompletionsCitationManager {
readonly _serviceBrand: undefined;
register(): IDisposable;
handleIPCodeCitation(citation: IPDocumentCitation): Promise<void>;
}
export class NoOpCitationManager implements ICompletionsCitationManager {
declare _serviceBrand: undefined;
register() { return Disposable.None; }
async handleIPCodeCitation(citation: IPDocumentCitation): Promise<void> {
// Do nothing
}
}
@@ -1,67 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import EventEmitter from 'events';
import { createServiceIdentifier } from '../../../../../util/common/services';
import { ICompletionsTelemetryService } from '../../bridge/src/completionsTelemetryServiceBridge';
import { CancellationToken, Disposable } from '../../types/src';
import { CompletionState } from './completionState';
import { GetGhostTextOptions } from './ghostText/ghostText';
import { telemetryCatch, TelemetryWithExp } from './telemetry';
import { ICompletionsPromiseQueueService } from './util/promiseQueue';
export type CompletionRequestedEvent = {
completionId: string;
completionState: CompletionState;
telemetryData: TelemetryWithExp;
cancellationToken?: CancellationToken;
options?: Partial<GetGhostTextOptions>;
};
const requestEventName = 'CompletionRequested';
export const ICompletionsNotifierService = createServiceIdentifier<ICompletionsNotifierService>('ICompletionsNotifierService');
export interface ICompletionsNotifierService {
readonly _serviceBrand: undefined;
notifyRequest(
completionState: CompletionState,
completionId: string,
telemetryData: TelemetryWithExp,
cancellationToken?: CancellationToken,
options?: Partial<GetGhostTextOptions>
): void;
onRequest(listener: (event: CompletionRequestedEvent) => void): Disposable;
}
export class CompletionNotifier implements ICompletionsNotifierService {
declare _serviceBrand: undefined;
#emitter = new EventEmitter();
constructor(
@ICompletionsPromiseQueueService protected completionsPromiseQueue: ICompletionsPromiseQueueService,
@ICompletionsTelemetryService protected completionsTelemetryService: ICompletionsTelemetryService,
) { }
notifyRequest(
completionState: CompletionState,
completionId: string,
telemetryData: TelemetryWithExp,
cancellationToken?: CancellationToken,
options?: Partial<GetGhostTextOptions>
) {
return this.#emitter.emit(requestEventName, {
completionId,
completionState,
telemetryData,
cancellationToken,
options,
});
}
onRequest(listener: (event: CompletionRequestedEvent) => void): Disposable {
const wrapper = telemetryCatch(this.completionsTelemetryService, this.completionsPromiseQueue, listener, `event.${requestEventName}`);
this.#emitter.on(requestEventName, wrapper);
return Disposable.create(() => this.#emitter.off(requestEventName, wrapper));
}
}
@@ -1,118 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Position, ProposedTextEdit, TextEdit } from '../../types/src';
import { IntelliSenseInsertion, ITextDocument, type TextDocumentContents } from './textDocument';
export class CompletionState {
readonly originalPosition: Position;
readonly originalVersion: number;
readonly originalOffset: number;
private readonly _editsWithPosition: ReadonlyArray<ProposedTextEdit>;
constructor(
private readonly _textDocument: ITextDocument,
private readonly _position: Position,
edits: ProposedTextEdit[] = [],
originalPosition?: Position,
originalVersion?: number,
originalOffset?: number
) {
this.originalPosition = originalPosition ?? Position.create(_position.line, _position.character);
this.originalVersion = originalVersion ?? _textDocument.version;
this.originalOffset = originalOffset ?? _textDocument.offsetAt(this.originalPosition);
this._editsWithPosition = [...edits];
}
get textDocument(): TextDocumentContents {
return this._textDocument;
}
get position(): Position {
return this._position;
}
get editsWithPosition(): ProposedTextEdit[] {
return [...this._editsWithPosition];
}
private updateState(textDocument: ITextDocument, position: Position, edits?: ProposedTextEdit[]): CompletionState {
return new CompletionState(
textDocument,
position,
edits ?? this.editsWithPosition,
this.originalPosition,
this.originalVersion,
this.originalOffset
);
}
updatePosition(position: Position): CompletionState {
return this.updateState(this._textDocument, position);
}
addSelectedCompletionInfo(selectedCompletionInfo: IntelliSenseInsertion): CompletionState {
if (this.editsWithPosition.find(edit => edit.source === 'selectedCompletionInfo')) {
throw new Error('Selected completion info already applied');
}
const edit: TextEdit = {
range: selectedCompletionInfo.range,
newText: selectedCompletionInfo.text,
};
return this.applyEdits([edit], true);
}
applyEdits(edits: TextEdit[], isSelectedCompletionInfo = false): CompletionState {
if (isSelectedCompletionInfo && edits.length > 1) {
throw new Error('Selected completion info should be a single edit');
}
let textDocument = this._textDocument;
let position = this._position;
let offset: number = textDocument.offsetAt(position);
const newEdits = this.editsWithPosition;
for (const { range, newText } of edits) {
const oldText = textDocument.getText(range);
const oldEndOffset = textDocument.offsetAt(range.end);
textDocument = textDocument.applyEdits([{ range, newText }]);
// We err on the side of updating the position if it's exactly aligned with the start of the range. This is
// what we want in the context of applying a completion, but it does make some operations impossible, like
// preserving a position at the start of the document (line 0 column 0).
if (offset < textDocument.offsetAt(range.start)) {
const edit: ProposedTextEdit = {
range,
newText,
positionAfterEdit: Position.create(position.line, position.character),
};
if (isSelectedCompletionInfo) {
edit.source = 'selectedCompletionInfo';
}
newEdits.push(edit);
continue;
}
if (offset < oldEndOffset) {
offset = oldEndOffset;
}
offset += newText.length - oldText.length;
position = textDocument.positionAt(offset);
const edit: ProposedTextEdit = {
range,
newText,
positionAfterEdit: Position.create(position.line, position.character),
};
if (isSelectedCompletionInfo) {
edit.source = 'selectedCompletionInfo';
}
newEdits.push(edit);
}
return this.updateState(textDocument, position, newEdits);
}
}
export function createCompletionState(textDocument: ITextDocument, position: Position): CompletionState {
return new CompletionState(textDocument, position);
}
@@ -1,22 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DocumentId } from '../../../../../platform/inlineEdits/common/dataTypes/documentId';
import { IObservableDocument } from '../../../../../platform/inlineEdits/common/observableWorkspace';
import { IObservableWithChange } from '../../../../../util/vs/base/common/observableInternal';
import { URI } from '../../../../../util/vs/base/common/uri';
import { createDecorator as createServiceIdentifier } from '../../../../../util/vs/platform/instantiation/common/instantiation';
export const ICompletionsObservableWorkspace = createServiceIdentifier<ICompletionsObservableWorkspace>('ICompletionsObservableWorkspace');
export interface ICompletionsObservableWorkspace {
readonly _serviceBrand: undefined;
get openDocuments(): IObservableWithChange<readonly IObservableDocument[], { added: readonly IObservableDocument[]; removed: readonly IObservableDocument[] }>;
getWorkspaceRoot(documentId: DocumentId): URI | undefined;
getFirstOpenDocument(): IObservableDocument | undefined;
getDocument(documentId: DocumentId): IObservableDocument | undefined;
}
-394
View File
@@ -1,394 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { packageJson } from '../../../../../platform/env/common/packagejson';
import { createServiceIdentifier } from '../../../../../util/common/services';
import { ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { CopilotConfigPrefix } from './constants';
import { Filter } from './experiments/filters';
import { Emitter, Event } from './util/event';
export { packageJson };
export const ConfigKey = {
Enable: 'enable',
UserSelectedCompletionModel: 'selectedCompletionModel',
ShowEditorCompletions: 'editor.showEditorCompletions',
EnableAutoCompletions: 'editor.enableAutoCompletions',
DelayCompletions: 'editor.delayCompletions',
FilterCompletions: 'editor.filterCompletions',
CompletionsDelay: 'completionsDelay',
CompletionsDebounce: 'completionsDebounce',
// Advanced config (don't add new config here)
RelatedFilesVSCodeCSharp: 'advanced.relatedFilesVSCodeCSharp',
RelatedFilesVSCodeTypeScript: 'advanced.relatedFilesVSCodeTypeScript',
RelatedFilesVSCode: 'advanced.relatedFilesVSCode',
ContextProviders: 'advanced.contextProviders',
DebugFilterLogCategories: 'advanced.debug.filterLogCategories',
DebugSnippyOverrideUrl: 'advanced.debug.codeRefOverrideUrl',
UseSubsetMatching: 'advanced.useSubsetMatching',
ContextProviderTimeBudget: 'advanced.contextProviderTimeBudget',
// Internal config
DebugOverrideCapiUrl: 'internal.capiUrl',
DebugOverrideCapiUrlLegacy: 'advanced.debug.overrideCapiUrl',
DebugTestOverrideCapiUrl: 'internal.capiTestUrl',
DebugTestOverrideCapiUrlLegacy: 'advanced.debug.testOverrideCapiUrl',
DebugOverrideProxyUrl: 'internal.completionsUrl',
DebugOverrideProxyUrlLegacy: 'advanced.debug.overrideProxyUrl',
DebugTestOverrideProxyUrl: 'internal.completionsTestUrl',
DebugTestOverrideProxyUrlLegacy: 'advanced.debug.testOverrideProxyUrl',
DebugOverrideEngine: 'internal.completionModel',
DebugOverrideEngineLegacy: 'advanced.debug.overrideEngine',
/**
* Internal experiment for always requesting multiline completions.
* This might not result always in a multiline suggestion, but most often will.
*/
AlwaysRequestMultiline: 'internal.alwaysRequestMultiline',
/**
* Let the model terminate single line completions when AlwaysRequestMultiline is enabled.
*/
ModelAlwaysTerminatesSingleline: 'internal.modelAlwaysTerminatesSingleline',
/**
* Overrides whether to use the Workspace Context Coordinator to coordinate workspace context.
* This setting takes precedence over the value from ExP.
*/
UseWorkspaceContextCoordinator: 'internal.useWorkspaceContextCoordinator',
/**
* Overrides whether to include neighboring files in the prompt
* alongside context providers.
* This setting takes precedence over the value from ExP.
*/
IncludeNeighboringFiles: 'internal.includeNeighboringFiles',
ExcludeRelatedFiles: 'internal.excludeRelatedFiles',
DebugOverrideCppHeadersEnableSwitch: 'internal.cppHeadersEnableSwitch',
/**
* Internal config for using the completions prompt with split context.
* https://github.com/github/copilot/issues/19286
*/
UseSplitContextPrompt: 'internal.useSplitContextPrompt',
};
export type ConfigKeyType = string;
// How to determine where to terminate the completion to the current block.
export enum BlockMode {
/**
* Parse the context + completion on the client using treesitter to
* determine blocks.
*/
Parsing = 'parsing',
/**
* Let the server parse out blocks and assume that the completion terminates
* at the end of a block.
*/
Server = 'server',
/**
* Runs both the treesitter parsing on the client plus indentation-based
* truncation on the proxy.
*/
ParsingAndServer = 'parsingandserver',
/**
* Client-based heuristic to display more multiline completions.
* It almost always requests a multiline completion from the server and tries to break it up to something useful on the client.
*
* This should not be rolled out at the moment (latency impact is high, UX needs further fine-tuning),
* but can be used for internal experimentation.
*/
MoreMultiline = 'moremultiline',
}
export function shouldDoServerTrimming(blockMode: BlockMode): boolean {
return [BlockMode.Server, BlockMode.ParsingAndServer].includes(blockMode);
}
// TODO rework this enum so that the normal/nightly and prod/dev distinctions are orthogonal. (dev builds should behave like nightly?)
export enum BuildType {
DEV = 'dev',
PROD = 'prod',
NIGHTLY = 'nightly',
}
export const ICompletionsConfigProvider = createServiceIdentifier<ICompletionsConfigProvider>('ICompletionsConfigProvider');
export interface ICompletionsConfigProvider {
readonly _serviceBrand: undefined;
getConfig<T>(key: ConfigKeyType): T;
getOptionalConfig<T>(key: ConfigKeyType): T | undefined;
dumpForTelemetry(): { [key: string]: string };
onDidChangeCopilotSettings: Event<ConfigProvider>;
}
export abstract class ConfigProvider implements ICompletionsConfigProvider {
declare _serviceBrand: undefined;
abstract getConfig<T>(key: ConfigKeyType): T;
abstract getOptionalConfig<T>(key: ConfigKeyType): T | undefined;
abstract dumpForTelemetry(): { [key: string]: string };
abstract onDidChangeCopilotSettings: Event<ConfigProvider>;
// The language server receives workspace configuration *after* it is fully initialized, which creates a race
// condition where an incoming request immediately after initialization might have the default values. Awaiting
// this promise allows consumers to ensure that the configuration is ready before using it.
requireReady(): Promise<void> {
return Promise.resolve();
}
}
/** Provides only the default values, ignoring the user's settings.
* @public KEEPING FOR TESTS
*/
export class DefaultsOnlyConfigProvider extends ConfigProvider {
override getConfig<T>(key: ConfigKeyType): T {
// hardcode default values for the agent, for now
return getConfigDefaultForKey<T>(key);
}
override getOptionalConfig<T>(key: ConfigKeyType): T | undefined {
return getOptionalConfigDefaultForKey<T>(key);
}
override dumpForTelemetry(): { [key: string]: string } {
return {};
}
override onDidChangeCopilotSettings = () => {
// no-op, since this provider does not support changing settings
return {
dispose: () => { },
};
};
}
/**
* A ConfigProvider that allows overriding of config values.
* @public KEEPING FOR TESTS
*/
export class InMemoryConfigProvider extends ConfigProvider {
protected readonly copilotEmitter = new Emitter<this>();
readonly onDidChangeCopilotSettings = this.copilotEmitter.event;
private overrides: Map<ConfigKeyType, unknown> = new Map();
constructor(
private readonly baseConfigProvider: ConfigProvider,
) {
super();
}
setOverrides(overrides: Map<ConfigKeyType, unknown>): void {
this.overrides = overrides;
}
clearOverrides(): void {
this.overrides.clear();
}
protected getOptionalOverride<T>(key: ConfigKeyType): T | undefined {
return this.overrides.get(key) as T | undefined;
}
override getConfig<T>(key: ConfigKeyType): T {
return this.getOptionalOverride(key) ?? this.baseConfigProvider.getConfig(key);
}
override getOptionalConfig<T>(key: ConfigKeyType): T | undefined {
return this.getOptionalOverride(key) ?? this.baseConfigProvider.getOptionalConfig(key);
}
setConfig(key: ConfigKeyType, value: unknown): void {
this.setCopilotSettings({ [key]: value });
}
setCopilotSettings(settings: Record<ConfigKeyType, unknown>): void {
for (const [key, value] of Object.entries(settings)) {
if (value !== undefined) {
this.overrides.set(key, value);
} else {
this.overrides.delete(key);
}
}
this.copilotEmitter.fire(this);
}
override dumpForTelemetry(): { [key: string]: string } {
const config = this.baseConfigProvider.dumpForTelemetry();
// reflects what's mapped in Hydro
for (const key of [
ConfigKey.ShowEditorCompletions,
ConfigKey.EnableAutoCompletions,
ConfigKey.DelayCompletions,
ConfigKey.FilterCompletions,
]) {
const value = this.overrides.get(key);
if (value !== undefined) {
config[key] = JSON.stringify(value);
}
}
return config;
}
}
export function getConfigKeyRecursively<T>(config: Record<string, unknown>, key: string): T | undefined {
let value: unknown = config;
const prefix: string[] = [];
for (const segment of key.split('.')) {
const child = [...prefix, segment].join('.');
if (value && typeof value === 'object' && child in value) {
value = (value as { [key: string]: unknown })[child];
prefix.length = 0;
} else {
prefix.push(segment);
}
}
if (value === undefined || prefix.length > 0) { return; }
return value as T;
}
export function getConfigDefaultForKey<T>(key: string): T {
if (configDefaults.has(key)) {
return configDefaults.get(key) as T;
}
throw new Error(`Missing config default value: ${CopilotConfigPrefix}.${key}`);
}
export function getOptionalConfigDefaultForKey<T>(key: string): T | undefined {
return <T>configDefaults.get(key);
}
/**
* Defaults for "hidden" config keys. These are supplemented by the defaults in package.json.
*/
const configDefaults = new Map<ConfigKeyType, unknown>([
[ConfigKey.DebugOverrideCppHeadersEnableSwitch, false],
[ConfigKey.RelatedFilesVSCodeCSharp, false],
[ConfigKey.RelatedFilesVSCodeTypeScript, false],
[ConfigKey.RelatedFilesVSCode, false],
[ConfigKey.IncludeNeighboringFiles, false],
[ConfigKey.ExcludeRelatedFiles, false],
[ConfigKey.ContextProviders, []],
[ConfigKey.DebugSnippyOverrideUrl, ''],
[ConfigKey.UseSubsetMatching, null],
[ConfigKey.ContextProviderTimeBudget, undefined],
[ConfigKey.DebugOverrideCapiUrl, ''],
[ConfigKey.DebugTestOverrideCapiUrl, ''],
[ConfigKey.DebugOverrideProxyUrl, ''],
[ConfigKey.DebugTestOverrideProxyUrl, ''],
[ConfigKey.DebugOverrideEngine, ''],
[ConfigKey.AlwaysRequestMultiline, undefined],
[ConfigKey.CompletionsDebounce, undefined],
[ConfigKey.CompletionsDelay, undefined],
[ConfigKey.ModelAlwaysTerminatesSingleline, undefined],
[ConfigKey.UseWorkspaceContextCoordinator, undefined],
// These are only used for telemetry from LSP based editors and do not affect any behavior.
[ConfigKey.ShowEditorCompletions, undefined],
[ConfigKey.EnableAutoCompletions, undefined],
[ConfigKey.DelayCompletions, undefined],
[ConfigKey.FilterCompletions, undefined],
[ConfigKey.UseSplitContextPrompt, true],
// These are defaults from package.json
[ConfigKey.Enable, { '*': true, 'plaintext': false, 'markdown': false, 'scminput': false }],
[ConfigKey.UserSelectedCompletionModel, ''],
// These are advanced defaults from package.json
[ConfigKey.DebugOverrideEngineLegacy, ''],
[ConfigKey.DebugOverrideProxyUrlLegacy, ''],
[ConfigKey.DebugTestOverrideProxyUrlLegacy, ''],
[ConfigKey.DebugOverrideCapiUrlLegacy, ''],
[ConfigKey.DebugTestOverrideCapiUrlLegacy, ''],
[ConfigKey.DebugFilterLogCategories, []],
]);
export function getConfig<T>(accessor: ServicesAccessor, key: ConfigKeyType): T {
return accessor.get(ICompletionsConfigProvider).getConfig(key);
}
export function dumpForTelemetry(accessor: ServicesAccessor) {
try {
return accessor.get(ICompletionsConfigProvider).dumpForTelemetry();
} catch (e) {
console.error(`Error dumping config for telemetry: ${e}`);
return {};
}
}
export class BuildInfo {
static isPreRelease(): boolean {
return this.getBuildType() === BuildType.NIGHTLY;
}
static isProduction(): boolean {
return this.getBuildType() !== BuildType.DEV;
}
static getBuildType(): BuildType {
const buildType = <'dev' | 'prod'>packageJson.buildType;
if (buildType === 'prod') {
return BuildInfo.getVersion().length === 15 ? BuildType.NIGHTLY : BuildType.PROD;
}
return BuildType.DEV;
}
static getVersion(): string {
return packageJson.version;
}
static getBuild(): string {
return packageJson.build;
}
}
type NameAndVersion = {
name: string;
version: string;
};
export type EditorInfo = NameAndVersion & {
// The root directory of the installation, currently only used to simplify stack traces.
root?: string;
// A programmatic name, used for error reporting.
devName?: string;
};
export type EditorPluginInfo = NameAndVersion;
export type EditorPluginFilter = { filter: Filter; value: string; isVersion?: boolean };
export function formatNameAndVersion({ name, version }: NameAndVersion): string {
return `${name}/${version}`;
}
export const ICompletionsEditorAndPluginInfo = createServiceIdentifier<ICompletionsEditorAndPluginInfo>('ICompletionsEditorAndPluginInfo');
export interface ICompletionsEditorAndPluginInfo {
readonly _serviceBrand: undefined;
getEditorInfo(): EditorInfo;
getEditorPluginInfo(): EditorPluginInfo;
getRelatedPluginInfo(): EditorPluginInfo[];
}
/**
* Do not use this in new code. Every endpoint has its own unique versioning.
* Centralizing in a single constant was a mistake.
* @deprecated
*/
export const apiVersion = '2025-05-01';
export function editorVersionHeaders(accessor: ServicesAccessor): { [key: string]: string } {
const info = accessor.get(ICompletionsEditorAndPluginInfo);
return {
'Editor-Version': formatNameAndVersion(info.getEditorInfo()),
'Editor-Plugin-Version': formatNameAndVersion(info.getEditorPluginInfo()),
'Copilot-Language-Server-Version': BuildInfo.getVersion(),
};
}
@@ -1,5 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const CopilotConfigPrefix = 'github.copilot';
@@ -1,41 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { Logger, logger } from './logger';
import { isAbortError } from './networking';
import { ICompletionsStatusReporter } from './progress';
const oomCodes = new Set(['ERR_WORKER_OUT_OF_MEMORY', 'ENOMEM']);
function isOomError(error: NodeJS.ErrnoException) {
return (
oomCodes.has(error.code ?? '') ||
// happens in loadWasmLanguage
(error.name === 'RangeError' && error.message === 'WebAssembly.Memory(): could not allocate memory')
);
}
export function handleException(accessor: ServicesAccessor, err: unknown, origin: string, _logger: Logger = logger): void {
if (isAbortError(err)) {
// ignore cancelled fetch requests
return;
}
const statusReporter = accessor.get(ICompletionsStatusReporter);
if (err instanceof Error) {
const error = err as NodeJS.ErrnoException;
if (isOomError(error)) {
statusReporter.setWarning('Out of memory');
} else if (error.code === 'EMFILE' || error.code === 'ENFILE') {
statusReporter.setWarning('Too many open files');
} else if (error.code === 'CopilotPromptLoadFailure') {
statusReporter.setWarning('Corrupted Copilot installation');
} else if (`${error.code}`.startsWith('CopilotPromptWorkerExit')) {
statusReporter.setWarning('Worker unexpectedly exited');
} else if (error.syscall === 'uv_cwd' && error.code === 'ENOENT') {
statusReporter.setWarning('Current working directory does not exist');
}
}
_logger.exception(accessor, err, origin);
}
@@ -1,79 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { BuildInfo, ICompletionsEditorAndPluginInfo } from './config';
import { TelemetryData } from './telemetry';
const os = {
EOL: '\n',
};
/** Diagnostics report made available in extension or agent. */
interface Report {
sections: Section[];
}
type SectionItems = { [key: string]: boolean | string | number | undefined };
/** Section of a diagnostics report. */
interface Section {
name: string;
items: SectionItems;
}
export function collectCompletionDiagnostics(accessor: ServicesAccessor, telemetry: TelemetryData | undefined): Report {
const telemetryItems: SectionItems = {};
if (telemetry !== undefined) {
if (telemetry.properties.headerRequestId) {
telemetryItems['Header Request ID'] = telemetry.properties.headerRequestId;
}
if (telemetry.properties.choiceIndex) {
telemetryItems['Choice Index'] = telemetry.properties.choiceIndex;
}
if (telemetry.properties.opportunityId) {
telemetryItems['Opportunity ID'] = telemetry.properties.opportunityId;
}
if (telemetry.properties.clientCompletionId) {
telemetryItems['Client Completion ID'] = telemetry.properties.clientCompletionId;
}
if (telemetry.properties.engineName) {
telemetryItems['Model ID'] = telemetry.properties.engineName;
}
}
return {
sections: [
{
name: 'Copilot Extension',
items: {
Version: BuildInfo.getVersion(),
Editor: getEditorDisplayVersion(accessor),
...telemetryItems,
},
},
],
};
}
export function formatDiagnosticsAsMarkdown(data: Report): string {
const s = data.sections.map(formatSectionAsMarkdown);
return s.join(os.EOL + os.EOL) + os.EOL;
}
function formatSectionAsMarkdown(s: Section) {
return (
`## ${s.name}` +
os.EOL +
os.EOL +
Object.keys(s.items)
.filter(k => k !== 'name')
.map(k => `- ${k}: ${s.items[k] ?? 'N/A'}`)
.join(os.EOL)
);
}
function getEditorDisplayVersion(accessor: ServicesAccessor): string {
const info = accessor.get(ICompletionsEditorAndPluginInfo).getEditorInfo();
return `${info.name} ${info.version}`;
}
@@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { LRUCacheMap } from './helpers/cache';
import { TextDocumentIdentifier } from './textDocument';
import { ICompletionsTextDocumentManagerService } from './textDocumentManager';
/**
* A map from the string representation of a document URI to its last access time in ms since the
* epoch.
*/
export const accessTimes = new LRUCacheMap<string, number>();
/**
* Returns a copy of `docs` sorted by access time, from most to least recent.
*/
export function sortByAccessTimes<T extends TextDocumentIdentifier>(docs: readonly T[]): T[] {
return [...docs].sort((a, b) => {
const aAccessTime = accessTimes.get(a.uri) ?? 0;
const bAccessTime = accessTimes.get(b.uri) ?? 0;
return bAccessTime - aAccessTime;
});
}
/**
* Registers a listener on the `window.onDidChangeActiveTextEditor` event that records/updates the
* access time of the document.
*/
export const registerDocumentTracker = (accessor: ServicesAccessor) =>
accessor.get(ICompletionsTextDocumentManagerService).onDidFocusTextDocument(e => {
if (e.document) {
accessTimes.set(e.document.uri.toString(), Date.now());
}
});
@@ -1,61 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IEnvService } from '../../../../../../platform/env/common/envService';
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { URI } from '../../../../../../util/vs/base/common/uri';
import { ICompletionsLogTargetService, Logger } from '../logger';
import { ICompletionsNotificationSender } from '../notificationSender';
const CERTIFICATE_ERRORS = ['UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'CERT_SIGNATURE_FAILURE'];
const errorMsg =
'Your proxy connection requires a trusted certificate. Please make sure the proxy certificate and any issuers are configured correctly and trusted by your operating system.';
const learnMoreLink = 'https://gh.io/copilot-network-errors';
export const ICompletionsUserErrorNotifierService = createServiceIdentifier<ICompletionsUserErrorNotifierService>('ICompletionsUserErrorNotifierService');
export interface ICompletionsUserErrorNotifierService {
readonly _serviceBrand: undefined;
notifyUser(e: unknown): void;
}
export class UserErrorNotifier implements ICompletionsUserErrorNotifierService {
declare _serviceBrand: undefined;
private readonly notifiedErrorCodes: string[] = [];
constructor(
@ICompletionsLogTargetService private readonly _logTarget: ICompletionsLogTargetService,
@ICompletionsNotificationSender private readonly _notificationSender: ICompletionsNotificationSender,
@IEnvService private readonly _env: IEnvService
) { }
notifyUser(e: unknown) {
if (!(e instanceof Error)) { return; }
const error: NodeJS.ErrnoException = e;
if (error.code && CERTIFICATE_ERRORS.includes(error.code) && !this.didNotifyBefore(error.code)) {
this.notifiedErrorCodes.push(error.code);
void this.displayCertificateErrorNotification(error);
}
}
private async displayCertificateErrorNotification(err: NodeJS.ErrnoException) {
new Logger('certificates').error(
this._logTarget,
`${errorMsg} Please visit ${learnMoreLink} to learn more. Original cause:`,
err
);
const learnMoreAction = { title: 'Learn more' };
return this._notificationSender
.showWarningMessage(errorMsg, learnMoreAction)
.then(userResponse => {
if (userResponse?.title === learnMoreAction.title) {
return this._env.openExternal(URI.parse(learnMoreLink));
}
});
}
private didNotifyBefore(code: string) {
return this.notifiedErrorCodes.indexOf(code) !== -1;
}
}
@@ -1,76 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAuthenticationService } from '../../../../../../platform/authentication/common/authentication';
import { IExperimentationService } from '../../../../../../platform/telemetry/common/nullExperimentationService';
import { IDisposable } from '../../../../../../util/vs/base/common/lifecycle';
import { IInstantiationService, ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { CopilotToken } from '../auth/copilotTokenManager';
import { getUserKind } from '../auth/orgs';
import {
BuildInfo,
BuildType,
ConfigKey,
getConfig
} from '../config';
import { getEngineRequestInfo } from '../openai/config';
import { Filter, Release } from './filters';
export function setupCompletionsExperimentationService(accessor: ServicesAccessor): IDisposable {
const authService = accessor.get(IAuthenticationService);
const instantiationService = accessor.get(IInstantiationService);
const disposable = authService.onDidAccessTokenChange(() => {
authService.getCopilotToken()
.then(t => instantiationService.invokeFunction(updateCompletionsFilters, t))
.catch(err => { });
});
updateCompletionsFilters(accessor, authService.copilotToken);
return disposable;
}
function getPluginRelease(accessor: ServicesAccessor): Release {
if (BuildInfo.getBuildType() === BuildType.NIGHTLY) {
return Release.Nightly;
}
return Release.Stable;
}
function updateCompletionsFilters(accessor: ServicesAccessor, token: Omit<CopilotToken, 'token'> | undefined) {
const exp = accessor.get(IExperimentationService);
const filters = createCompletionsFilters(accessor, token);
exp.setCompletionsFilters(filters);
}
export function createCompletionsFilters(accessor: ServicesAccessor, token: Omit<CopilotToken, 'token'> | undefined) {
const filters = new Map<Filter, string>();
filters.set(Filter.ExtensionRelease, getPluginRelease(accessor));
filters.set(Filter.CopilotOverrideEngine, getConfig(accessor, ConfigKey.DebugOverrideEngine) || getConfig(accessor, ConfigKey.DebugOverrideEngineLegacy));
filters.set(Filter.CopilotClientVersion, BuildInfo.isProduction() ? BuildInfo.getVersion() : '1.999.0');
if (token) {
const userKind = getUserKind(token);
const customModel = token.getTokenValue('ft') ?? '';
const orgs = token.getTokenValue('ol') ?? '';
const customModelNames = token.getTokenValue('cml') ?? '';
const copilotTrackingId = token.getTokenValue('tid') ?? '';
filters.set(Filter.CopilotUserKind, userKind);
filters.set(Filter.CopilotCustomModel, customModel);
filters.set(Filter.CopilotOrgs, orgs);
filters.set(Filter.CopilotCustomModelNames, customModelNames);
filters.set(Filter.CopilotTrackingId, copilotTrackingId);
filters.set(Filter.CopilotUserKind, getUserKind(token));
}
const model = getEngineRequestInfo(accessor).modelId;
filters.set(Filter.CopilotEngine, model);
return filters;
}
@@ -1,154 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { TelemetryData, telemetryExpProblem } from '../telemetry';
import { ExpServiceTelemetryNames } from './telemetryNames';
// All variables we pull from Exp and might want to use
export enum ExpTreatmentVariables {
// the engine we want to request, used in actual experiment(s)
CustomEngine = 'copilotcustomengine',
// if set, any custom engine (see previous) will only apply when the current engine matches the value of this variable
CustomEngineTargetEngine = 'copilotcustomenginetargetengine',
OverrideBlockMode = 'copilotoverrideblockmode',
SuffixPercent = 'CopilotSuffixPercent', // the percentage of the prompt tokens to allocate to the suffix
CppHeadersEnableSwitch = 'copilotcppheadersenableswitch', // whether to enable the inclusion of C++ headers as neighbors in the prompt
UseSubsetMatching = 'copilotsubsetmatching', // whether to use subset matching instead of jaccard similarity experiment
// granularity specification
SuffixMatchThreshold = 'copilotsuffixmatchthreshold', // the threshold that new suffix should match with old suffix
MaxPromptCompletionTokens = 'maxpromptcompletionTokens', // the maximum tokens of the prompt and completion
/**
* Enable the use of the Workspace Context Coordinator to coordinate context from providers of workspace snippets.
*/
StableContextPercent = 'copilotstablecontextpercent', // the percentage of the prompt tokens to allocate to the stable context
VolatileContextPercent = 'copilotvolatilecontextpercent', // the percentage of the prompt tokens to allocate to the volatile context
/**
* Flags that control the enablement of the related files extensibility for various languages in VSCode.
*/
RelatedFilesVSCodeCSharp = 'copilotrelatedfilesvscodecsharp', // whether to include related files as neighbors in the prompt for C#, this takes precedence over RelatedFilesVSCode
RelatedFilesVSCodeTypeScript = 'copilotrelatedfilesvscodetypescript', // whether to include related files as neighbors in the prompt for TS/JS, this takes precedence over RelatedFilesVSCode
RelatedFilesVSCode = 'copilotrelatedfilesvscode', // whether to include related files as neighbors in the prompt, vscode experiment
/**
* Flags that control the inclusion of open tab files as neighboring files for various languages.
*/
ContextProviders = 'copilotcontextproviders', // comma-separated list of context providers IDs (case sensitive) to enable
IncludeNeighboringFiles = 'copilotincludeneighboringfiles', // Always include neighboring files alongside context providers
ExcludeRelatedFiles = 'copilotexcluderelatedfiles', // Exclude related files even if neighboring files are enabled
ContextProviderTimeBudget = 'copilotcontextprovidertimebudget', // time budget for context providers in milliseconds
/**
* Values to control the ContextProvider API's CodeSnippets provided by the C++ Language Service.
*/
CppContextProviderParams = 'copilotcppContextProviderParams',
/**
* Values to control the ContextProvider API's CodeSnippets provided by the C# Language Service.
*/
CSharpContextProviderParams = 'copilotcsharpcontextproviderparams',
/**
* Values to control the ContextProvider API's CodeSnippets provided by the Java Language Service.
*/
JavaContextProviderParams = 'copilotjavacontextproviderparams',
/**
* Values to control the MultiLanguageContextProvider parameters.
*/
MultiLanguageContextProviderParams = 'copilotmultilanguagecontextproviderparams',
/**
* Values to control the TsContextProvider parameters.
*/
TsContextProviderParams = 'copilottscontextproviderparams',
/**
* Controls the delay to apply to debouncing of completion requests.
*/
CompletionsDebounce = 'copilotcompletionsdebounce',
/**
* Enable the electron networking in VS Code.
*/
ElectronFetcher = 'copilotelectronfetcher',
FetchFetcher = 'copilotfetchfetcher',
/**
* Sets the timeout for waiting for async completions in flight before
* issuing a new network request. Set to -1 to disable the timeout entirely.
*/
AsyncCompletionsTimeout = 'copilotasynccompletionstimeout',
/**
* Controls whether the prompt context for code completions needs to be split from the document prefix.
*/
EnablePromptContextProxyField = 'copilotenablepromptcontextproxyfield',
/**
* Controls progressive reveal of completions.
*/
ProgressiveReveal = 'copilotprogressivereveal',
// part of progressive reveal, controls whether the model or client terminates single-line completions
ModelAlwaysTerminatesSingleline = 'copilotmodelterminatesingleline',
// long look-ahead window size (in lines) for progressive reveal
ProgressiveRevealLongLookaheadSize = 'copilotprogressivereveallonglookaheadsize',
// short look-ahead window size (in lines) for progressive reveal
ProgressiveRevealShortLookaheadSize = 'copilotprogressiverevealshortlookaheadsize',
// maximum token count when requesting multi-line completions
MaxMultilineTokens = 'copilotmaxmultilinetokens',
/**
* Controls number of lines to trim to after accepting a completion.
*/
MultilineAfterAcceptLines = 'copilotmultilineafteracceptlines',
/**
* Add a delay before rendering completions.
*/
CompletionsDelay = 'copilotcompletionsdelay',
/**
* Request single line completions unless the previous completion was just accepted.
*/
SingleLineUnlessAccepted = 'copilotsinglelineunlessaccepted',
}
export type ExpTreatmentVariableValue = boolean | string | number;
export class ExpConfig {
variables: Partial<Record<ExpTreatmentVariables, ExpTreatmentVariableValue>>; // for the 'vscode' config
features: string; // semicolon-separated feature IDs
constructor(
variables: Partial<Record<ExpTreatmentVariables, ExpTreatmentVariableValue>>,
features: string
) {
this.variables = variables;
this.features = features;
}
static createFallbackConfig(accessor: ServicesAccessor, reason: string): ExpConfig {
telemetryExpProblem(accessor, { reason });
return this.createEmptyConfig();
}
static createEmptyConfig() {
return new ExpConfig({}, '');
}
/**
* Adds (or overwrites) the given experiment config to the telemetry data.
* @param telemetryData telemetryData object. If previous ExpConfigs are already present, they will be overwritten.
*/
addToTelemetry(telemetryData: TelemetryData): void {
telemetryData.properties[ExpServiceTelemetryNames.featuresTelemetryPropertyName] = this.features;
}
}
@@ -1,415 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService } from '../../../../../../platform/log/common/logService';
import { IExperimentationService } from '../../../../../../platform/telemetry/common/nullExperimentationService';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import {
DEFAULT_MAX_COMPLETION_LENGTH,
DEFAULT_MAX_PROMPT_LENGTH,
DEFAULT_PROMPT_ALLOCATION_PERCENT,
DEFAULT_SUFFIX_MATCH_THRESHOLD
} from '../../../prompt/src/prompt';
import { CopilotToken, ICompletionsCopilotTokenManager } from '../auth/copilotTokenManager';
import { BlockMode } from '../config';
import { TelemetryData, TelemetryWithExp } from '../telemetry';
import { createCompletionsFilters } from './defaultExpFilters';
import { ExpConfig, ExpTreatmentVariables, ExpTreatmentVariableValue } from './expConfig';
import { CompletionsFiltersInfo, ContextProviderExpSettings, ICompletionsFeaturesService } from './featuresService';
import { Filter, FilterSettings } from './filters';
type InternalContextProviderExpSettings = {
id?: string;
ids?: string[];
includeNeighboringFiles?: boolean;
excludeRelatedFiles?: boolean;
timeBudget?: number;
params?: Record<string, string | boolean | number>;
};
/** General-purpose API for accessing ExP variable values. */
export class Features implements ICompletionsFeaturesService {
declare _serviceBrand: undefined;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IExperimentationService private readonly experimentationService: IExperimentationService,
@ICompletionsCopilotTokenManager private readonly copilotTokenManager: ICompletionsCopilotTokenManager,
) { }
/**
* Central logic for obtaining the assignments of treatment groups
* for a given set of filters (i.e. descriptors of who is getting the treatment).
* Also gets the values of variables controlled by experiment.
*
* This function should be called **exactly once** at the start of every
* 'completion request' in the client (e.g. ghostText, panel request or chat conversation).
*
* It is called with an initial set of filters, (FeaturesFilterArgs)
* but it adds many of its own.
* At first the general background filters like extension version.
* Then it will check ExP assignments for the first time, to find out
* whether there are any assignments of a special granularity
* (i.e. the concept that we want to redraw assignments based on
* time bucket, or checksum of time, etc).
*
* On most calls to this function, the assignment fetches will be the
* assignments from previously used filters, so they will be cached and return fast.
*
* @param telemetryData The base telemetry object to which the experimental filters, ExP
* variable values, and experimental assignments will be added. All properties and measurements
* of the input telemetryData will be present in the output TelemetryWithExp object.
* Every telemetry data used to generate ExP scorecards (e.g. ghostText events) must
* include the correct experiment assignments in order to properly create those
* scorecards.
*/
async updateExPValuesAndAssignments(
filtersInfo?: CompletionsFiltersInfo,
telemetryData: TelemetryData = TelemetryData.createAndMarkAsIssued()
): Promise<TelemetryWithExp> {
// We should not allow accidentally overwriting existing ExP vals/assignments.
// This doesn't stop all misuse cases, but should prevent some trivial ones.
if (telemetryData instanceof TelemetryWithExp) {
throw new Error('updateExPValuesAndAssignments should not be called with TelemetryWithExp');
}
const token = this.copilotTokenManager.token ?? await this.copilotTokenManager.getToken();
const { filters, exp } = this.createExpConfigAndFilters(token);
return new TelemetryWithExp(telemetryData.properties, telemetryData.measurements, telemetryData.issuedTime, {
filters,
exp: exp,
});
}
/**
* Request a Copilot token and use that token to call updateExPValuesAndAssignments. Do NOT call this at startup.
* Instead, register a onCopilotToken handler and use that token with updateExPValuesAndAssignments directly.
*/
async fetchTokenAndUpdateExPValuesAndAssignments(
filtersInfo?: CompletionsFiltersInfo,
telemetryData?: TelemetryData
) {
return await this.updateExPValuesAndAssignments(filtersInfo, telemetryData);
}
private createExpConfigAndFilters(token: CopilotToken) {
const exp2: Partial<Record<ExpTreatmentVariables, ExpTreatmentVariableValue>> = {};
for (const varName of Object.values<ExpTreatmentVariables>(ExpTreatmentVariables)) {
const value = this.experimentationService.getTreatmentVariable(varName);
if (value !== undefined) {
exp2[varName] = value;
}
}
const features = Object.entries(exp2).map(([name, value]) => {
// Based on what tas-client does in https://github.com/microsoft/tas-client/blob/2bd24c976273b671892aad99139af2c7c7dc3b26/tas-client/src/tas-client/FeatureProvider/TasApiFeatureProvider.ts#L59
return name + (value ? '' : 'cf');
});
const exp = new ExpConfig(exp2, features.join(';'));
const filterMap = this.instantiationService.invokeFunction(createCompletionsFilters, token);
const filterRecord: Partial<Record<Filter, string>> = {};
for (const [key, value] of filterMap.entries()) {
filterRecord[key] = value;
}
const filters = new FilterSettings(filterRecord);
return { filters, exp };
}
/** Get the entries from this.assignments corresponding to given settings. */
async getFallbackExpAndFilters(): Promise<{ filters: FilterSettings; exp: ExpConfig }> {
const token = this.copilotTokenManager.token ?? await this.copilotTokenManager.getToken();
return this.createExpConfigAndFilters(token);
}
/** Override for BlockMode to send in the request. */
overrideBlockMode(telemetryWithExp: TelemetryWithExp): BlockMode | undefined {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.OverrideBlockMode] as BlockMode) ||
undefined
);
}
/** Functions with arguments, passed via object destructuring */
/** @returns the string for copilotcustomengine, or "" if none is set. */
customEngine(telemetryWithExp: TelemetryWithExp): string {
return (telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.CustomEngine] as string) ?? '';
}
/** @returns the string for copilotcustomenginetargetengine, or undefined if none is set. */
customEngineTargetEngine(telemetryWithExp: TelemetryWithExp): string | undefined {
return telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.CustomEngineTargetEngine] as string;
}
/** @returns the percent of prompt tokens to be allocated to the suffix */
suffixPercent(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.SuffixPercent] as number) ??
DEFAULT_PROMPT_ALLOCATION_PERCENT.suffix
);
}
/** @returns the percentage match threshold for using the cached suffix */
suffixMatchThreshold(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.SuffixMatchThreshold] as number) ??
DEFAULT_SUFFIX_MATCH_THRESHOLD
);
}
/** @returns whether to enable the inclusion of C++ headers as neighbor files. */
cppHeadersEnableSwitch(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.CppHeadersEnableSwitch] as boolean) ??
false
);
}
/** @returns whether to use included related files as neighbor files for C# (vscode experiment). */
relatedFilesVSCodeCSharp(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.RelatedFilesVSCodeCSharp] as boolean) ??
false
);
}
/** @returns whether to use included related files as neighbor files for TS/JS (vscode experiment). */
relatedFilesVSCodeTypeScript(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.RelatedFilesVSCodeTypeScript
] as boolean) ?? false
);
}
/** @returns whether to use included related files as neighbor files (vscode experiment). */
relatedFilesVSCode(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.RelatedFilesVSCode] as boolean) ?? false
);
}
/** @returns the list of context providers IDs to enable. The special value `*` enables all context providers. */
contextProviders(telemetryWithExp: TelemetryWithExp): string[] {
const providers = (telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.ContextProviders] ??
'') as string;
if (!providers) {
return [];
}
return providers.split(',').map(provider => provider.trim());
}
contextProviderTimeBudget(languageId: string, telemetryWithExp: TelemetryWithExp): number {
const client = (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.ContextProviderTimeBudget] as number) ??
150
);
if (client) {
return client;
}
const chat = this.getContextProviderExpSettings(languageId);
return chat?.timeBudget ?? 150;
}
includeNeighboringFiles(languageId: string, telemetryWithExp: TelemetryWithExp): boolean {
const client = (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.IncludeNeighboringFiles] as boolean) ??
false
);
if (client) {
return true;
}
const chat = this.getContextProviderExpSettings(languageId);
return chat?.includeNeighboringFiles ?? false;
}
excludeRelatedFiles(languageId: string, telemetryWithExp: TelemetryWithExp): boolean {
const client = (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.ExcludeRelatedFiles] as boolean) ??
false
);
if (client) {
return true;
}
const chat = this.getContextProviderExpSettings(languageId);
return chat?.excludeRelatedFiles ?? false;
}
getContextProviderExpSettings(languageId: string): ContextProviderExpSettings | undefined {
const value = this.experimentationService.getTreatmentVariable<string>(`config.github.copilot.chat.contextprovider.${languageId}`);
if (typeof value === 'string') {
try {
const parsed: Partial<InternalContextProviderExpSettings> = JSON.parse(value);
const ids = this.getProviderIDs(parsed);
delete parsed.id;
delete parsed.ids;
return Object.assign({ ids }, { includeNeighboringFiles: false, excludeRelatedFiles: false, timeBudget: 150 }, parsed as Omit<InternalContextProviderExpSettings, 'id' | 'ids'>);
} catch (err) {
this.instantiationService.invokeFunction((accessor) => {
const logService = accessor.get(ILogService);
logService.error(`Failed to parse context provider exp settings for language ${languageId}`);
});
return undefined;
}
} else {
return undefined;
}
}
private getProviderIDs(json: InternalContextProviderExpSettings): string[] {
const result: string[] = [];
if (typeof json.id === 'string' && json.id.length > 0) {
result.push(json.id);
}
if (Array.isArray(json.ids)) {
for (const id of json.ids) {
if (typeof id === 'string' && id.length > 0) {
result.push(id);
}
}
}
return result;
}
/** @returns the maximal number of tokens of prompt AND completion */
maxPromptCompletionTokens(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.MaxPromptCompletionTokens] as number) ??
DEFAULT_MAX_PROMPT_LENGTH + DEFAULT_MAX_COMPLETION_LENGTH
);
}
stableContextPercent(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.StableContextPercent] as number) ??
DEFAULT_PROMPT_ALLOCATION_PERCENT.stableContext
);
}
volatileContextPercent(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.VolatileContextPercent] as number) ??
DEFAULT_PROMPT_ALLOCATION_PERCENT.volatileContext
);
}
/** Custom parameters for language specific Context Providers. */
cppContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined {
const cppContextProviderParams = telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.CppContextProviderParams
] as string;
return cppContextProviderParams;
}
csharpContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined {
const csharpContextProviderParams = telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.CSharpContextProviderParams
] as string;
return csharpContextProviderParams;
}
javaContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined {
const javaContextProviderParams = telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.JavaContextProviderParams
] as string;
return javaContextProviderParams;
}
multiLanguageContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined {
const multiLanguageContextProviderParams = telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.MultiLanguageContextProviderParams
] as string;
return multiLanguageContextProviderParams;
}
tsContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined {
const tsContextProviderParams = telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.TsContextProviderParams
] as string;
return tsContextProviderParams;
}
completionsDebounce(telemetryWithExp: TelemetryWithExp): number | undefined {
return telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.CompletionsDebounce] as
| number
| undefined;
}
enableElectronFetcher(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.ElectronFetcher] as boolean) ?? false
);
}
enableFetchFetcher(telemetryWithExp: TelemetryWithExp): boolean {
return (telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.FetchFetcher] as boolean) ?? false;
}
asyncCompletionsTimeout(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.AsyncCompletionsTimeout] as number) ??
200
);
}
enableProgressiveReveal(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.ProgressiveReveal] as boolean) ?? false
);
}
modelAlwaysTerminatesSingleline(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.ModelAlwaysTerminatesSingleline
] as boolean) ?? true
);
}
longLookaheadSize(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.ProgressiveRevealLongLookaheadSize
] as number) ?? 9
);
}
shortLookaheadSize(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[
ExpTreatmentVariables.ProgressiveRevealShortLookaheadSize
] as number) ?? 3
);
}
maxMultilineTokens(telemetryWithExp: TelemetryWithExp): number {
// p50 line length is 19 characters (p95 is 73)
// average token length is around 4 characters
// the below value has quite a bit of buffer while bringing the limit in significantly from 500
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.MaxMultilineTokens] as number) ?? 200
);
}
multilineAfterAcceptLines(telemetryWithExp: TelemetryWithExp): number {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.MultilineAfterAcceptLines] as number) ??
1
);
}
completionsDelay(telemetryWithExp: TelemetryWithExp): number {
return (telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.CompletionsDelay] as number) ?? 200;
}
singleLineUnlessAccepted(telemetryWithExp: TelemetryWithExp): boolean {
return (
(telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.SingleLineUnlessAccepted] as boolean) ??
false
);
}
}
@@ -1,68 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { BlockMode } from '../config';
import { TelemetryData, TelemetryWithExp } from '../telemetry';
import { ExpConfig } from './expConfig';
import { FilterSettings } from './filters';
export type CompletionsFiltersInfo = { uri: string; languageId: string };
export type ContextProviderExpSettings = {
ids: string[];
includeNeighboringFiles: boolean;
excludeRelatedFiles: boolean;
timeBudget: number;
params?: Record<string, string | boolean | number>;
}
export const ICompletionsFeaturesService = createServiceIdentifier<ICompletionsFeaturesService>('ICompletionsFeaturesService');
export interface ICompletionsFeaturesService {
readonly _serviceBrand: undefined;
updateExPValuesAndAssignments(
filtersInfo?: CompletionsFiltersInfo,
telemetryData?: TelemetryData
): Promise<TelemetryWithExp>;
fetchTokenAndUpdateExPValuesAndAssignments(
filtersInfo?: CompletionsFiltersInfo,
telemetryData?: TelemetryData
): Promise<TelemetryWithExp>;
getFallbackExpAndFilters(): Promise<{ filters: FilterSettings; exp: ExpConfig }>;
overrideBlockMode(telemetryWithExp: TelemetryWithExp): BlockMode | undefined;
customEngine(telemetryWithExp: TelemetryWithExp): string;
customEngineTargetEngine(telemetryWithExp: TelemetryWithExp): string | undefined;
suffixPercent(telemetryWithExp: TelemetryWithExp): number;
suffixMatchThreshold(telemetryWithExp: TelemetryWithExp): number;
cppHeadersEnableSwitch(telemetryWithExp: TelemetryWithExp): boolean;
relatedFilesVSCodeCSharp(telemetryWithExp: TelemetryWithExp): boolean;
relatedFilesVSCodeTypeScript(telemetryWithExp: TelemetryWithExp): boolean;
relatedFilesVSCode(telemetryWithExp: TelemetryWithExp): boolean;
contextProviders(telemetryWithExp: TelemetryWithExp): string[];
contextProviderTimeBudget(languageId: string, telemetryWithExp: TelemetryWithExp): number;
includeNeighboringFiles(languageId: string, telemetryWithExp: TelemetryWithExp): boolean;
excludeRelatedFiles(languageId: string, telemetryWithExp: TelemetryWithExp): boolean;
getContextProviderExpSettings(languageId: string): ContextProviderExpSettings | undefined;
maxPromptCompletionTokens(telemetryWithExp: TelemetryWithExp): number;
stableContextPercent(telemetryWithExp: TelemetryWithExp): number;
volatileContextPercent(telemetryWithExp: TelemetryWithExp): number;
cppContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined;
csharpContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined;
javaContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined;
multiLanguageContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined;
tsContextProviderParams(telemetryWithExp: TelemetryWithExp): string | undefined;
completionsDebounce(telemetryWithExp: TelemetryWithExp): number | undefined;
enableElectronFetcher(telemetryWithExp: TelemetryWithExp): boolean;
enableFetchFetcher(telemetryWithExp: TelemetryWithExp): boolean;
asyncCompletionsTimeout(telemetryWithExp: TelemetryWithExp): number;
enableProgressiveReveal(telemetryWithExp: TelemetryWithExp): boolean;
modelAlwaysTerminatesSingleline(telemetryWithExp: TelemetryWithExp): boolean;
longLookaheadSize(telemetryWithExp: TelemetryWithExp): number;
shortLookaheadSize(telemetryWithExp: TelemetryWithExp): number;
maxMultilineTokens(telemetryWithExp: TelemetryWithExp): number;
multilineAfterAcceptLines(telemetryWithExp: TelemetryWithExp): number;
completionsDelay(telemetryWithExp: TelemetryWithExp): number;
singleLineUnlessAccepted(telemetryWithExp: TelemetryWithExp): boolean;
}
@@ -1,105 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TelemetryData } from '../telemetry';
/** The prefix used for related plugin version headers. */
const CopilotRelatedPluginVersionPrefix = 'X-Copilot-RelatedPluginVersion-';
/** The filter headers that ExP knows about. */
export enum Filter {
// Default VSCode filters
ExtensionRelease = 'X-VSCode-ExtensionRelease',
// Copilot-specific filters
/** The machine ID concatenated with a 1-hour bucket. */
CopilotClientTimeBucket = 'X-Copilot-ClientTimeBucket',
/** The model currently in use. Not included in fallback filters */
CopilotEngine = 'X-Copilot-Engine',
/** The engine override value from settings, if present. */
CopilotOverrideEngine = 'X-Copilot-OverrideEngine',
/** Git repo info. Not included in fallback filters */
CopilotRepository = 'X-Copilot-Repository',
/** Language of the file on which a given request is being made. Not included in fallback filters */
CopilotFileType = 'X-Copilot-FileType', // Wired to languageId
/** The organization the user belongs to. Not included in fallback filters */
CopilotUserKind = 'X-Copilot-UserKind',
/** Declare experiment dogfood program if any. Not included in fallback filters */
CopilotDogfood = 'X-Copilot-Dogfood',
/** For custom Model Alpha. Not included in fallback filters */
CopilotCustomModel = 'X-Copilot-CustomModel',
/** Organizations. */
CopilotOrgs = 'X-Copilot-Orgs',
/** Identifiers for Custom Model(s) */
CopilotCustomModelNames = 'X-Copilot-CustomModelNames',
/** Copilot Tracking ID */
CopilotTrackingId = 'X-Copilot-CopilotTrackingId',
/** The Copilot Client Version */
CopilotClientVersion = 'X-Copilot-ClientVersion',
CopilotRelatedPluginVersionCppTools = CopilotRelatedPluginVersionPrefix + 'msvscodecpptools',
CopilotRelatedPluginVersionCMakeTools = CopilotRelatedPluginVersionPrefix + 'msvscodecmaketools',
CopilotRelatedPluginVersionMakefileTools = CopilotRelatedPluginVersionPrefix + 'msvscodemakefiletools',
CopilotRelatedPluginVersionCSharpDevKit = CopilotRelatedPluginVersionPrefix + 'msdotnettoolscsdevkit',
CopilotRelatedPluginVersionPython = CopilotRelatedPluginVersionPrefix + 'mspythonpython',
CopilotRelatedPluginVersionPylance = CopilotRelatedPluginVersionPrefix + 'mspythonvscodepylance',
CopilotRelatedPluginVersionJavaPack = CopilotRelatedPluginVersionPrefix + 'vscjavavscodejavapack',
CopilotRelatedPluginVersionJavaManager = CopilotRelatedPluginVersionPrefix + 'vscjavavscodejavadependency',
CopilotRelatedPluginVersionTypescript = CopilotRelatedPluginVersionPrefix + 'vscodetypescriptlanguagefeatures',
CopilotRelatedPluginVersionTypescriptNext = CopilotRelatedPluginVersionPrefix + 'msvscodevscodetypescriptnext',
CopilotRelatedPluginVersionCSharp = CopilotRelatedPluginVersionPrefix + 'msdotnettoolscsharp',
CopilotRelatedPluginVersionGithubCopilotChat = CopilotRelatedPluginVersionPrefix + 'githubcopilotchat',
CopilotRelatedPluginVersionGithubCopilot = CopilotRelatedPluginVersionPrefix + 'githubcopilot',
}
export enum Release {
Stable = 'stable',
Nightly = 'nightly',
}
const telmetryNames: Partial<Record<Filter, string>> = {
[Filter.CopilotClientTimeBucket]: 'timeBucket',
[Filter.CopilotOverrideEngine]: 'engine',
[Filter.CopilotRepository]: 'repo',
[Filter.CopilotFileType]: 'fileType',
[Filter.CopilotUserKind]: 'userKind',
};
/**
* The class FilterSettings holds the variables that were used to filter
* experiment groups.
*/
export class FilterSettings {
constructor(private readonly filters: Partial<Record<Filter, string>>) {
// empyt string is equivalent to absent, so remove it
for (const [filter, value] of Object.entries(this.filters)) {
if (value === '') {
delete this.filters[filter as Filter];
}
}
}
/**
* Extends the telemetry Data with the current filter variables.
* @param telemetryData Extended in place.
*/
addToTelemetry(telemetryData: TelemetryData) {
// add all values:
for (const [filter, value] of Object.entries(this.filters)) {
const telemetryName = telmetryNames[filter as Filter];
if (telemetryName === undefined) {
continue;
}
telemetryData.properties[telemetryName] = value;
}
}
/** Returns a copy of the filters. */
toHeaders(): Partial<Record<Filter, string>> {
return { ...this.filters };
}
}
@@ -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.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { DEFAULT_NUM_SNIPPETS } from '../../../prompt/src/prompt';
import { defaultSimilarFilesOptions, SimilarFilesOptions } from '../../../prompt/src/snippetInclusion/similarFiles';
import { ConfigKey, getConfig } from '../config';
import { TelemetryWithExp } from '../telemetry';
import { ExpTreatmentVariables } from './expConfig';
import { getCppNumberOfSnippets, getCppSimilarFilesOptions } from './similarFileOptionsProviderCpp';
type SimilarFilesOptionsProvider = (accessor: ServicesAccessor, exp: TelemetryWithExp) => SimilarFilesOptions;
// Add here for more options for other language ids.
const languageSimilarFilesOptions: ReadonlyMap<string, SimilarFilesOptionsProvider> = new Map<
string,
SimilarFilesOptionsProvider
>([['cpp', getCppSimilarFilesOptions]]);
export function getSimilarFilesOptions(accessor: ServicesAccessor, exp: TelemetryWithExp, langId: string): SimilarFilesOptions {
const optionsProvider: SimilarFilesOptionsProvider | undefined = languageSimilarFilesOptions.get(langId);
if (optionsProvider) {
return optionsProvider(accessor, exp);
} else {
return {
...defaultSimilarFilesOptions,
useSubsetMatching: useSubsetMatching(accessor, exp),
};
}
}
type NumberOfSnippetsProvider = (exp: TelemetryWithExp) => number;
// Add here for more values for other language ids.
const numberOfSnippets: ReadonlyMap<string, NumberOfSnippetsProvider> = new Map<string, NumberOfSnippetsProvider>([
['cpp', getCppNumberOfSnippets],
]);
export function getNumberOfSnippets(exp: TelemetryWithExp, langId: string): number {
const provider: NumberOfSnippetsProvider | undefined = numberOfSnippets.get(langId);
return provider ? provider(exp) : DEFAULT_NUM_SNIPPETS;
}
export function useSubsetMatching(accessor: ServicesAccessor, telemetryWithExp: TelemetryWithExp): boolean {
return (
((telemetryWithExp.filtersAndExp.exp.variables[ExpTreatmentVariables.UseSubsetMatching] as boolean) ||
getConfig(accessor, ConfigKey.UseSubsetMatching)) ??
false
);
}
@@ -1,20 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServicesAccessor } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { defaultCppSimilarFilesOptions, SimilarFilesOptions } from '../../../prompt/src/snippetInclusion/similarFiles';
import { TelemetryWithExp } from '../telemetry';
import { useSubsetMatching } from './similarFileOptionsProvider';
export function getCppSimilarFilesOptions(accessor: ServicesAccessor, telemetryWithExp: TelemetryWithExp): SimilarFilesOptions {
return {
...defaultCppSimilarFilesOptions,
useSubsetMatching: useSubsetMatching(accessor, telemetryWithExp),
};
}
export function getCppNumberOfSnippets(telemetryWithExp: TelemetryWithExp): number {
return defaultCppSimilarFilesOptions.maxTopSnippets;
}
@@ -1,10 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export enum ExpServiceTelemetryNames {
// these are defined (but not exported) in the code for the tas client, currently here:
// https://github.com/microsoft/tas-client/blob/75f8895b15ef5696653cbee134ccae24477b0b94/vscode-tas-client/src/vscode-tas-client/VSCodeTasClient.ts#L67
featuresTelemetryPropertyName = 'VSCode.ABExp.Features',
}
@@ -1,51 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ServicesAccessor } from '../../../../../../../util/vs/platform/instantiation/common/instantiation';
import { extractRepoInfoInBackground } from '../../prompt/repository';
import { TelemetryData } from '../../telemetry';
import { createLibTestingContext } from '../../test/context';
import { makeFsUri } from '../../util/uri';
import { ICompletionsFeaturesService } from '../featuresService';
suite('updateExPValuesAndAssignments', function () {
let accessor: ServicesAccessor;
const filenameUri = makeFsUri(__filename);
setup(async function () {
accessor = createLibTestingContext().createTestingAccessor();
// Trigger extractRepoInfoInBackground early + add a sleep to force repo info to be available
extractRepoInfoInBackground(accessor, filenameUri);
await new Promise(resolve => setTimeout(resolve, 100));
});
test('If no options are provided, repo filters should be empty and there should be no telemetry properties or measurements', async function () {
const featuresService = accessor.get(ICompletionsFeaturesService);
const telemetry = await featuresService.updateExPValuesAndAssignments();
assert.deepStrictEqual(telemetry.properties, {});
assert.deepStrictEqual(telemetry.measurements, {});
const filters = telemetry.filtersAndExp.filters.toHeaders();
assert.deepStrictEqual(filters['X-Copilot-Repository'], undefined);
assert.deepStrictEqual(filters['X-Copilot-FileType'], undefined);
});
test('If telemetry data is passed as a parameter, it should be used in the resulting telemetry object', async function () {
const telemetryData = TelemetryData.createAndMarkAsIssued({ foo: 'bar' }, { baz: 42 });
const featuresService = accessor.get(ICompletionsFeaturesService);
const telemetry = await featuresService.updateExPValuesAndAssignments(undefined, telemetryData);
assert.deepStrictEqual(telemetry.properties, { foo: 'bar' });
assert.deepStrictEqual(telemetry.measurements, { baz: 42 });
const filters = telemetry.filtersAndExp.filters.toHeaders();
assert.deepStrictEqual(filters['X-Copilot-Repository'], undefined);
assert.deepStrictEqual(filters['X-Copilot-FileType'], undefined);
});
});
@@ -1,86 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../util/common/services';
import { IInstantiationService } from '../../../../../util/vs/platform/instantiation/common/instantiation';
import { ICompletionsFileSystemService } from './fileSystem';
import { CopilotTextDocument, ITextDocument, TextDocumentIdentifier, TextDocumentResult } from './textDocument';
import { ICompletionsTextDocumentManagerService } from './textDocumentManager';
import { isDocumentValid } from './util/documentEvaluation';
import { basename } from './util/uri';
export const ICompletionsFileReaderService = createServiceIdentifier<ICompletionsFileReaderService>('ICompletionsFileReaderService');
export interface ICompletionsFileReaderService {
readonly _serviceBrand: undefined;
getRelativePath(doc: TextDocumentIdentifier): string | undefined;
getOrReadTextDocument(doc: TextDocumentIdentifier): Promise<TextDocumentResult>;
getOrReadTextDocumentWithFakeClientProperties(
doc: TextDocumentIdentifier
): Promise<TextDocumentResult<ITextDocument>>;
}
export class FileReader implements ICompletionsFileReaderService {
declare _serviceBrand: undefined;
constructor(
@ICompletionsTextDocumentManagerService private readonly documentManagerService: ICompletionsTextDocumentManagerService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICompletionsFileSystemService private readonly fileSystemService: ICompletionsFileSystemService,
) { }
getRelativePath(doc: TextDocumentIdentifier) {
return this.documentManagerService.getRelativePath(doc) ?? basename(doc.uri);
}
getOrReadTextDocument(doc: TextDocumentIdentifier): Promise<TextDocumentResult> {
return this.readFile(doc.uri);
}
getOrReadTextDocumentWithFakeClientProperties(
doc: TextDocumentIdentifier
): Promise<TextDocumentResult<ITextDocument>> {
return this.readFile(doc.uri);
}
/**
* @deprecated use `getOrReadTextDocument` instead
*/
protected async readFile(uri: string): Promise<TextDocumentResult<ITextDocument>> {
const documentResult = await this.documentManagerService.getTextDocumentWithValidation({ uri });
if (documentResult.status !== 'notfound') {
return documentResult;
}
try {
const fileSizeMB = await this.getFileSizeMB(uri);
// Note: the real production behavior actually blocks files larger than 5MB
if (fileSizeMB > 1) {
// Using notfound instead of invalid because of the mapping in statusFromTextDocumentResult
return { status: 'notfound' as const, message: 'File too large' };
}
const text = await this.doReadFile(uri);
// Note, that we check for blocked files even for empty files!
const rcmResult = await this.instantiationService.invokeFunction(isDocumentValid, { uri });
if (rcmResult.status === 'valid') {
const doc = CopilotTextDocument.create(uri, 'UNKNOWN', -1, text);
return { status: 'valid' as const, document: doc };
}
return rcmResult;
} catch (e) {
return { status: 'notfound' as const, message: 'File not found' };
}
}
private async doReadFile(uri: string) {
return await this.fileSystemService.readFileString(uri);
}
private async getFileSizeMB(uri: string) {
const stat = await this.fileSystemService.stat(uri);
return stat.size / 1024 / 1024;
}
}
@@ -1,67 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../util/common/services';
/**
* `FileType` identifies the type of a file. `SymbolicLink` may be combined
* with other types, e.g. `FileType.Directory | FileType.SymbolicLink`.
*/
export enum FileType {
/** The file type is not known. */
Unknown = 0,
/** The file is a regular file. */
File = 1,
/** The file is a directory. */
Directory = 2,
/** The file is a symbolic link. */
SymbolicLink = 64,
}
/**
* The `FileStat`-type represents metadata about a file
*/
export interface FileStat {
/**
* The creation timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
*/
ctime: number;
/**
* The modification timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
*
* *Note:* If the file changed, it is important to provide an updated `mtime` that advanced
* from the previous value. Otherwise there may be optimizations in place that will not show
* the updated file contents in an editor for example.
*/
mtime: number;
/**
* The size in bytes.
*
* *Note:* If the file changed, it is important to provide an updated `size`. Otherwise there
* may be optimizations in place that will not show the updated file contents in an editor for
* example.
*/
size: number;
/**
* The type of file.
*
* *Note:* This is a bit field. Multiple flags may be set on it, e.g.
* `FileType.File | FileType.SymbolicLink`.
*/
type: FileType;
}
export type FileIdentifier = string | { readonly uri: string };
export const ICompletionsFileSystemService = createServiceIdentifier<ICompletionsFileSystemService>('ICompletionsFileSystemService');
export interface ICompletionsFileSystemService {
readonly _serviceBrand: undefined;
readFileString(uri: FileIdentifier): Promise<string>;
stat(uri: FileIdentifier): Promise<FileStat>;
readDirectory(uri: FileIdentifier): Promise<[string, FileType][]>;
}
@@ -1,309 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { CancellationTokenSource } from '../../../types/src';
import { ICompletionsFeaturesService } from '../experiments/featuresService';
import { LRUCacheMap } from '../helpers/cache';
import { ICompletionsLogTargetService, Logger } from '../logger';
import { APIChoice } from '../openai/openai';
import { Prompt } from '../prompt/prompt';
import { TelemetryWithExp } from '../telemetry';
import { Deferred } from '../util/async';
import { ReplaySubject } from '../util/subject';
import { GetNetworkCompletionsType } from './ghostText';
enum AsyncCompletionRequestState {
Completed,
Error,
Pending,
}
interface BaseAsyncCompletionRequest {
cancellationTokenSource: CancellationTokenSource;
headerRequestId: string;
partialCompletionText?: string;
prefix: string;
prompt: Prompt;
subject: ReplaySubject<AsyncCompletionRequest>;
}
interface PendingAsyncCompletionRequest extends BaseAsyncCompletionRequest {
state: AsyncCompletionRequestState.Pending;
}
interface CompletedAsyncCompletionRequest extends BaseAsyncCompletionRequest {
state: AsyncCompletionRequestState.Completed;
choice: APIChoice;
result: GetNetworkCompletionsType;
allChoicesPromise: Promise<void>;
}
type AsyncCompletionRequest = PendingAsyncCompletionRequest | CompletedAsyncCompletionRequest;
export const ICompletionsAsyncManagerService = createServiceIdentifier<ICompletionsAsyncManagerService>('ICompletionsAsyncManagerService');
export interface ICompletionsAsyncManagerService {
readonly _serviceBrand: undefined;
clear(): void;
shouldWaitForAsyncCompletions(prefix: string, prompt: Prompt): boolean;
updateCompletion(headerRequestId: string, text: string): void;
queueCompletionRequest(
headerRequestId: string,
prefix: string,
prompt: Prompt,
cancellationTokenSource: CancellationTokenSource,
resultPromise: Promise<GetNetworkCompletionsType>
): Promise<void>;
getFirstMatchingRequestWithTimeout(
headerRequestId: string,
prefix: string,
prompt: Prompt,
isSpeculative: boolean,
telemetryWithExp: TelemetryWithExp
): Promise<[APIChoice, Promise<void>] | undefined>;
getFirstMatchingRequest(
headerRequestId: string,
prefix: string,
prompt: Prompt,
isSpeculative: boolean
): Promise<[APIChoice, Promise<void>] | undefined>;
}
export class AsyncCompletionManager implements ICompletionsAsyncManagerService {
declare _serviceBrand: undefined;
#logger = new Logger('AsyncCompletionManager');
/** Mapping of headerRequestId to completion request */
private readonly requests = new LRUCacheMap<string, AsyncCompletionRequest>(100);
/** The most recently requested (either via getFirstMatchingRequest or
* getFirstMatchingRequestWithTimeout) header request ID. Serves as a lock
* for cancellation. Since we only want to cancel requests that don't match
* the most recent request prefix. */
private mostRecentRequestId = '';
constructor(
@ICompletionsFeaturesService private readonly featuresService: ICompletionsFeaturesService,
@ICompletionsLogTargetService private readonly logTarget: ICompletionsLogTargetService,
) { }
clear() {
this.requests.clear();
}
/**
* Check if there are any candidate completions for the current position.
* We need to strike the right balance between queuing completions as the
* user types, without queuing one per keystroke. This method should return
* true if we don't have any completions that match the current position.
* This method should return false if we have reasonable candidates that
* match the current position.
*/
shouldWaitForAsyncCompletions(prefix: string, prompt: Prompt): boolean {
// TODO: Consider adding a minimum threshold for candidate completions,
// where we will queue more if the user's typing seems to be diverging
// from current speculation.
for (const [_, request] of this.requests) {
if (isCandidate(prefix, prompt, request)) {
return true;
}
}
return false;
}
/**
* Called from a FinishedCallback to report partial results as a completion
* is streamed back from the server.
*/
updateCompletion(headerRequestId: string, text: string) {
const request = this.requests.get(headerRequestId);
if (request === undefined) { return; }
request.partialCompletionText = text;
request.subject.next(request);
}
/**
* Adds an in-flight completion request to the requests map for tracking.
* Once the request is completed it is removed from the requests map.
*/
queueCompletionRequest(
headerRequestId: string,
prefix: string,
prompt: Prompt,
cancellationTokenSource: CancellationTokenSource,
resultPromise: Promise<GetNetworkCompletionsType>
) {
this.#logger.debug(this.logTarget,
`[${headerRequestId}] Queueing async completion request:`,
prefix.substring(prefix.lastIndexOf('\n') + 1)
);
const subject = new ReplaySubject<AsyncCompletionRequest>();
this.requests.set(headerRequestId, {
state: AsyncCompletionRequestState.Pending,
cancellationTokenSource,
headerRequestId,
prefix,
prompt,
subject,
});
return resultPromise
.then(result => {
this.requests.delete(headerRequestId);
if (result.type !== 'success') {
this.#logger.debug(this.logTarget, `[${headerRequestId}] Request failed with`, result.reason);
subject.error(result.reason);
return;
}
const completed: CompletedAsyncCompletionRequest = {
cancellationTokenSource,
headerRequestId,
prefix,
prompt,
subject,
choice: result.value[0],
result,
state: AsyncCompletionRequestState.Completed,
allChoicesPromise: result.value[1],
};
this.requests.set(headerRequestId, completed);
subject.next(completed);
subject.complete();
})
.catch((e: unknown) => {
this.#logger.error(this.logTarget, `[${headerRequestId}] Request errored with`, e);
this.requests.delete(headerRequestId);
subject.error(e);
});
}
/** Returns the first matching completion or times out. */
getFirstMatchingRequestWithTimeout(
headerRequestId: string,
prefix: string,
prompt: Prompt,
isSpeculative: boolean,
telemetryWithExp: TelemetryWithExp
): Promise<[APIChoice, Promise<void>] | undefined> {
const timeout = this.featuresService.asyncCompletionsTimeout(telemetryWithExp);
if (timeout < 0) {
this.#logger.debug(this.logTarget, `[${headerRequestId}] Waiting for completions without timeout`);
return this.getFirstMatchingRequest(headerRequestId, prefix, prompt, isSpeculative);
}
this.#logger.debug(this.logTarget, `[${headerRequestId}] Waiting for completions with timeout of ${timeout}ms`);
return Promise.race([
this.getFirstMatchingRequest(headerRequestId, prefix, prompt, isSpeculative),
new Promise<null>(r => setTimeout(() => r(null), timeout)),
]).then(result => {
if (result === null) {
this.#logger.debug(this.logTarget, `[${headerRequestId}] Timed out waiting for completion`);
return undefined;
}
return result;
});
}
/**
* Returns the first resolved matching completion request. Modifies the
* returned APIChoice to match the current prompt.
*/
async getFirstMatchingRequest(
headerRequestId: string,
prefix: string,
prompt: Prompt,
isSpeculative: boolean
): Promise<[APIChoice, Promise<void>] | undefined> {
if (!isSpeculative) { this.mostRecentRequestId = headerRequestId; }
let resolved = false;
const deferred = new Deferred<[APIChoice, Promise<void>] | undefined>();
const subscriptions = new Map<string, () => void>();
const finishRequest = (id: string) => () => {
const subscription = subscriptions.get(id);
if (subscription === undefined) { return; }
subscription();
subscriptions.delete(id);
if (!resolved && subscriptions.size === 0) {
// TODO: Check for new candidates before resolving.
resolved = true;
this.#logger.debug(this.logTarget, `[${headerRequestId}] No matching completions found`);
deferred.resolve(undefined);
}
};
const next = (request: AsyncCompletionRequest) => {
if (isCandidate(prefix, prompt, request)) {
if (request.state === AsyncCompletionRequestState.Completed) {
const remainingPrefix = prefix.substring(request.prefix.length);
let { completionText } = request.choice;
if (
!completionText.startsWith(remainingPrefix) ||
completionText.length <= remainingPrefix.length
) {
finishRequest(request.headerRequestId)();
return;
}
completionText = completionText.substring(remainingPrefix.length);
request.choice.telemetryData.measurements.foundOffset = remainingPrefix.length;
this.#logger.debug(this.logTarget,
`[${headerRequestId}] Found completion at offset ${remainingPrefix.length}: ${JSON.stringify(completionText)}`
);
deferred.resolve([{ ...request.choice, completionText }, request.allChoicesPromise]);
resolved = true;
}
} else {
this.cancelRequest(headerRequestId, request);
finishRequest(request.headerRequestId)();
}
};
for (const [id, request] of this.requests) {
if (isCandidate(prefix, prompt, request)) {
subscriptions.set(
id,
request.subject.subscribe({
next,
error: finishRequest(id),
complete: finishRequest(id),
})
);
} else {
this.cancelRequest(headerRequestId, request);
}
}
return deferred.promise.finally(() => {
for (const dispose of subscriptions.values()) {
dispose();
}
});
}
/**
* Attempts to cancel a request if it is still pending and the request
* attempting the cancellation (that it no longer matches) is the most
* recent request.
*
* @param headerRequestId The request id for the call to
* getFirstMatchingRequest that the `request` no longer matches.
* @param request The request to cancel
*/
private cancelRequest(headerRequestId: string, request: AsyncCompletionRequest) {
if (headerRequestId !== this.mostRecentRequestId) { return; }
if (request.state === AsyncCompletionRequestState.Completed) { return; }
this.#logger.debug(this.logTarget, `[${headerRequestId}] Cancelling request: ${request.headerRequestId}`);
request.cancellationTokenSource.cancel();
this.requests.delete(request.headerRequestId);
}
}
function isCandidate(prefix: string, prompt: Prompt, request: AsyncCompletionRequest): boolean {
if (request.prompt.suffix !== prompt.suffix) { return false; }
if (!prefix.startsWith(request.prefix)) { return false; }
const remainingPrefix = prefix.substring(request.prefix.length);
if (request.state === AsyncCompletionRequestState.Completed) {
return (
request.choice.completionText.startsWith(remainingPrefix) &&
request.choice.completionText.trimEnd().length > remainingPrefix.length
);
}
if (request.partialCompletionText === undefined) { return true; }
return request.partialCompletionText.startsWith(remainingPrefix);
}
@@ -1,328 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { StatementNode, StatementTree } from './statementTree';
import { IPosition, TextDocumentContents } from '../textDocument';
/**
* BlockTrimmer base class.
*/
export abstract class BlockTrimmer {
static isSupported(languageId: string): boolean {
return StatementTree.isSupported(languageId);
}
/** Tests for the subset of supported languages that are trimmed by default */
static isTrimmedByDefault(languageId: string): boolean {
return StatementTree.isTrimmedByDefault(languageId);
}
constructor(
protected readonly languageId: string,
protected readonly prefix: string,
protected readonly completion: string
) { }
abstract getCompletionTrimOffset(): Promise<number | undefined>;
protected async withParsedStatementTree<T>(fn: (tree: StatementTree) => Promise<T> | T): Promise<T> {
const tree = StatementTree.create(
this.languageId,
this.prefix + this.completion,
this.prefix.length,
this.prefix.length + this.completion.length
);
await tree.build();
try {
return await fn(tree);
} finally {
tree[Symbol.dispose]();
}
}
protected trimmedCompletion(offset: number | undefined): string {
return offset === undefined ? this.completion : this.completion.substring(0, offset);
}
/**
* Gets the statement at the cursor position.
* If the cursor is not within a statement (e.g. it's on an error node),
* returns the first statement from the tree (if any).
*/
protected getStatementAtCursor(tree: StatementTree): StatementNode | undefined {
return tree.statementAt(Math.max(this.prefix.length - 1, 0)) ?? tree.statements[0];
}
protected getContainingBlockOffset(stmt: StatementNode | undefined): number | undefined {
let trimTo: StatementNode | undefined;
if (stmt && this.isCompoundStatement(stmt)) {
// for compound statement types, trim to the current statement
trimTo = stmt;
} else if (stmt) {
// for non-compound statement types, trim to the closest compound ancestor
let parent = stmt.parent;
while (parent && !this.isCompoundStatement(parent)) {
parent = parent.parent;
}
trimTo = parent;
}
if (trimTo) {
const newOffset = this.asCompletionOffset(trimTo.node.endIndex);
// don't trim trailing whitespace as that will terminate the completion prematurely
if (newOffset && this.completion.substring(newOffset).trim() !== '') { return newOffset; }
}
return undefined;
}
protected hasNonStatementContentAfter(stmt: StatementNode | undefined): boolean {
if (!stmt || !stmt.nextSibling) { return false; }
const spanStart = this.asCompletionOffset(stmt.node.endIndex);
const spanEnd = this.asCompletionOffset(stmt.nextSibling.node.startIndex);
const content = this.completion.substring(Math.max(0, spanStart ?? 0), Math.max(0, spanEnd ?? 0));
return content.trim() !== '';
}
protected asCompletionOffset(offset: number | undefined): number | undefined {
return offset === undefined ? undefined : offset - this.prefix.length;
}
protected isCompoundStatement(stmt: StatementNode): boolean {
return stmt.isCompoundStatementType || stmt.children.length > 0;
}
}
/**
* A block trimmer that tries to obtain the longest reasonable completion
* within its line limit. This results in a more verbose completion.
*
* Don't delete it is used in tests.
*/
export class VerboseBlockTrimmer extends BlockTrimmer {
private readonly offsetLimit: number | undefined;
constructor(
languageId: string,
prefix: string,
completion: string,
private readonly lineLimit: number = 10
) {
super(languageId, prefix, completion);
// determine the end of the lineLimit line as an offset into the completion
const completionLineEnds = [...this.completion.matchAll(/\n/g)];
if (completionLineEnds.length >= this.lineLimit && this.lineLimit > 0) {
this.offsetLimit = completionLineEnds[this.lineLimit - 1].index;
} else {
this.offsetLimit = undefined;
}
}
async getCompletionTrimOffset(): Promise<number | undefined> {
return await this.withParsedStatementTree(tree => {
const stmt = this.getStatementAtCursor(tree);
// do not go past the containing block
let offset = this.getContainingBlockOffset(stmt);
// first try trimming at a blank line
if (!this.isWithinLimit(offset)) {
offset = this.trimToBlankLine(offset);
}
// then try trimming at a statement
if (!this.isWithinLimit(offset)) {
offset = this.trimToStatement(stmt, offset);
}
return offset;
});
}
private isWithinLimit(offset: number | undefined): boolean {
return this.offsetLimit === undefined || (offset !== undefined && offset <= this.offsetLimit);
}
private trimToBlankLine(offset: number | undefined): number | undefined {
const blankLines = [...this.trimmedCompletion(offset).matchAll(/\r?\n\s*\r?\n/g)].reverse();
while (blankLines.length > 0 && !this.isWithinLimit(offset)) {
const match = blankLines.pop()!;
offset = match.index;
}
return offset;
}
private trimToStatement(stmt: StatementNode | undefined, offset: number | undefined): number | undefined {
const min = this.prefix.length;
const max = this.prefix.length + (this.offsetLimit ?? this.completion.length);
let s = stmt;
let next = stmt?.nextSibling;
while (next && next.node.endIndex <= max && !this.hasNonStatementContentAfter(s)) {
s = next;
next = next.nextSibling;
}
if (s && s === stmt && s.node.endIndex <= min) {
s = next;
}
if (s && s.node.endIndex > max) {
// break at an internal statement if possible
return this.trimToStatement(s.children[0], this.asCompletionOffset(s.node.endIndex));
}
return this.asCompletionOffset(s?.node?.endIndex) ?? offset;
}
}
/**
* A block trimmer that stops when it's likely the end of a logical section has
* been reached, such as the start of a new compound statement. This results in
* a more terse completion.
*/
export class TerseBlockTrimmer extends BlockTrimmer {
private readonly limitOffset: number | undefined;
private readonly lookAheadOffset: number | undefined;
constructor(
languageId: string,
prefix: string,
completion: string,
private readonly lineLimit: number = 3,
private readonly lookAhead: number = 7
) {
super(languageId, prefix, completion);
// determine the end of the lineLimit line as an offset into the completion
const completionLineEnds = [...this.completion.matchAll(/\n/g)];
const limitAndLookAhead = this.lineLimit + this.lookAhead;
if (completionLineEnds.length >= this.lineLimit && this.lineLimit > 0) {
this.limitOffset = completionLineEnds[this.lineLimit - 1].index;
}
if (completionLineEnds.length >= limitAndLookAhead && limitAndLookAhead > 0) {
this.lookAheadOffset = completionLineEnds[limitAndLookAhead - 1].index;
}
}
async getCompletionTrimOffset(): Promise<number | undefined> {
return await this.withParsedStatementTree(tree => {
const stmt = tree.statementAt(this.stmtStartPos());
// do not go past the containing block
let offset = this.getContainingBlockOffset(stmt);
// trim at any blank lines
offset = this.trimAtFirstBlankLine(offset);
// trim at new blocks starts or areas of comments
if (stmt) {
offset = this.trimAtStatementChange(stmt, offset);
}
// hard trim at the line limit if we have enough context
if (this.limitOffset && this.lookAheadOffset && (offset === undefined || offset > this.lookAheadOffset)) {
return this.limitOffset;
}
return offset;
});
}
/**
* Return the position of the first non-whitespace character to the right
* of the cursor, or the start of the completion if it is blank.
*/
private stmtStartPos(): number {
const match = this.completion.match(/\S/);
if (match && match.index !== undefined) {
return this.prefix.length + match.index;
}
return Math.max(this.prefix.length - 1, 0);
}
private trimAtFirstBlankLine(offset: number | undefined): number | undefined {
const blankLines = [...this.trimmedCompletion(offset).matchAll(/\r?\n\s*\r?\n/g)];
while (blankLines.length > 0 && (offset === undefined || offset > blankLines[0].index)) {
const match = blankLines.shift()!;
if (this.completion.substring(0, match.index).trim() !== '') {
return match.index;
}
}
return offset;
}
private trimAtStatementChange(stmt: StatementNode, offset: number | undefined): number | undefined {
const min = this.prefix.length;
const max = this.prefix.length + (offset ?? this.completion.length);
// if the first statement is a compound statement, trim to the first statement
if (stmt.node.endIndex > min && this.isCompoundStatement(stmt)) {
// if we have a next sibling, the statement is likely finished
if (stmt.nextSibling && stmt.node.endIndex < max) {
return this.asCompletionOffset(stmt.node.endIndex);
}
return offset;
}
// otherwise, stop at the first compound statement or non-statement content
let s = stmt;
let next = stmt.nextSibling;
while (
next &&
next.node.endIndex <= max &&
!this.hasNonStatementContentAfter(s) &&
!this.isCompoundStatement(next)
) {
s = next;
next = next.nextSibling;
}
if (next && s.node.endIndex > min && s.node.endIndex < max) {
return this.asCompletionOffset(s.node.endIndex);
}
return offset;
}
}
export enum BlockPositionType {
NonBlock = 'non-block',
EmptyBlock = 'empty-block',
BlockEnd = 'block-end',
MidBlock = 'mid-block',
}
export async function getBlockPositionType(
document: TextDocumentContents,
position: IPosition
): Promise<BlockPositionType> {
const text = document.getText();
const offset = document.offsetAt(position);
const tree = StatementTree.create(document.detectedLanguageId, text, 0, text.length);
try {
await tree.build();
const stmt = tree.statementAt(offset);
if (!stmt) { return BlockPositionType.NonBlock; }
if (!stmt.isCompoundStatementType && stmt.children.length === 0) {
if (stmt.parent && !stmt.nextSibling && stmt.node.endPosition.row <= position.line) {
return BlockPositionType.BlockEnd;
} else if (stmt.parent) {
return BlockPositionType.MidBlock;
}
return BlockPositionType.NonBlock;
}
if (stmt.children.length === 0) {
return BlockPositionType.EmptyBlock;
}
const lastChild = stmt.children[stmt.children.length - 1];
if (offset < lastChild.node.startIndex) {
return BlockPositionType.MidBlock;
}
return BlockPositionType.BlockEnd;
} finally {
tree[Symbol.dispose]();
}
}
@@ -1,69 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { LRURadixTrie } from '../helpers/radix';
import { APIChoice } from '../openai/openai';
interface CompletionsCacheContents {
content: {
suffix: string;
choice: APIChoice;
}[];
}
export const ICompletionsCacheService = createServiceIdentifier<ICompletionsCacheService>('ICompletionsCacheService');
export interface ICompletionsCacheService {
readonly _serviceBrand: undefined;
/** Given a document prefix and suffix, return all of the completions that match. */
findAll(prefix: string, suffix: string): APIChoice[];
/** Add cached completions for a given prefix. */
append(prefix: string, suffix: string, choice: APIChoice): void;
clear(): void;
}
/** Caches recent completions by document prefix. */
export class CompletionsCache implements ICompletionsCacheService {
readonly _serviceBrand: undefined;
private cache = new LRURadixTrie<CompletionsCacheContents>(100);
/** Given a document prefix and suffix, return all of the completions that match. */
findAll(prefix: string, suffix: string): APIChoice[] {
return this.cache.findAll(prefix).flatMap(({ remainingKey, value }) =>
value.content
.filter(
c =>
c.suffix === suffix &&
c.choice.completionText.startsWith(remainingKey) &&
c.choice.completionText.length > remainingKey.length
)
.map(c => ({
...c.choice,
completionText: c.choice.completionText.slice(remainingKey.length),
telemetryData: c.choice.telemetryData.extendedBy({}, { foundOffset: remainingKey.length }),
}))
);
}
/** Add cached completions for a given prefix. */
append(prefix: string, suffix: string, choice: APIChoice) {
const existing = this.cache.findAll(prefix);
// Append to an existing array if there is an exact match.
if (existing.length > 0 && existing[0].remainingKey === '') {
const content = existing[0].value.content;
this.cache.set(prefix, { content: [...content, { suffix, choice }] });
} else {
// Otherwise, add a new value.
this.cache.set(prefix, { content: [{ suffix, choice }] });
}
}
clear() {
this.cache = new LRURadixTrie<CompletionsCacheContents>(100);
}
}
@@ -1,74 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// The following code was moved from config.ts into here to break the cyclic dependencies
import { createServiceIdentifier } from '../../../../../../util/common/services';
import { IInstantiationService } from '../../../../../../util/vs/platform/instantiation/common/instantiation';
import { BlockMode } from '../../../../../completions/common/config';
import { isSupportedLanguageId } from '../../../prompt/src/parse';
import { ConfigKey, getConfig } from '../config';
import { ICompletionsFeaturesService } from '../experiments/featuresService';
import { TelemetryWithExp } from '../telemetry';
import { BlockTrimmer } from './blockTrimmer';
import { StatementTree } from './statementTree';
export const ICompletionsBlockModeConfig = createServiceIdentifier<ICompletionsBlockModeConfig>('ICompletionsBlockModeConfig');
export interface ICompletionsBlockModeConfig {
readonly _serviceBrand: undefined;
forLanguage(languageId: string, telemetryData: TelemetryWithExp): BlockMode;
}
export class ConfigBlockModeConfig implements ICompletionsBlockModeConfig {
declare _serviceBrand: undefined;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICompletionsFeaturesService private readonly featuresService: ICompletionsFeaturesService,
) { }
forLanguage(languageId: string, telemetryData: TelemetryWithExp): BlockMode {
const overrideBlockMode = this.featuresService.overrideBlockMode(telemetryData);
if (overrideBlockMode) {
return toApplicableBlockMode(overrideBlockMode, languageId);
}
const progressiveReveal = this.featuresService.enableProgressiveReveal(telemetryData);
const config = this.instantiationService.invokeFunction(getConfig, ConfigKey.AlwaysRequestMultiline);
if (config ?? progressiveReveal) {
return toApplicableBlockMode(BlockMode.MoreMultiline, languageId);
}
if (BlockTrimmer.isTrimmedByDefault(languageId)) {
return toApplicableBlockMode(BlockMode.MoreMultiline, languageId);
}
// special casing once cancellations based on tree-sitter propagate to
// the proxy.
if (languageId === 'ruby') {
return BlockMode.Parsing;
}
// For existing multiline languages use standard tree-sitter based parsing
// plus proxy-side trimming
if (isSupportedLanguageId(languageId)) {
return BlockMode.ParsingAndServer;
}
return BlockMode.Server;
}
}
function blockModeRequiresTreeSitter(blockMode: BlockMode): boolean {
return [BlockMode.Parsing, BlockMode.ParsingAndServer, BlockMode.MoreMultiline].includes(blockMode);
}
/**
* Prevents tree-sitter parsing from being applied to languages we don't include
* parsers for.
*/
function toApplicableBlockMode(blockMode: BlockMode, languageId: string): BlockMode {
if (blockMode === BlockMode.MoreMultiline && StatementTree.isSupported(languageId)) {
return blockMode;
}
if (blockModeRequiresTreeSitter(blockMode) && !isSupportedLanguageId(languageId)) {
return BlockMode.Server;
}
return blockMode;
}
@@ -1,101 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const contextualFilterCharacterMap: { [key: string]: number } = {
' ': 1,
'!': 2,
'"': 3,
'#': 4,
$: 5,
'%': 6,
'&': 7,
'\'': 8,
'(': 9,
')': 10,
'*': 11,
'+': 12,
',': 13,
'-': 14,
'.': 15,
'/': 16,
'0': 17,
'1': 18,
'2': 19,
'3': 20,
'4': 21,
'5': 22,
'6': 23,
'7': 24,
'8': 25,
'9': 26,
':': 27,
';': 28,
'<': 29,
'=': 30,
'>': 31,
'?': 32,
'@': 33,
A: 34,
B: 35,
C: 36,
D: 37,
E: 38,
F: 39,
G: 40,
H: 41,
I: 42,
J: 43,
K: 44,
L: 45,
M: 46,
N: 47,
O: 48,
P: 49,
Q: 50,
R: 51,
S: 52,
T: 53,
U: 54,
V: 55,
W: 56,
X: 57,
Y: 58,
Z: 59,
'[': 60,
'\\': 61,
']': 62,
'^': 63,
_: 64,
'`': 65,
a: 66,
b: 67,
c: 68,
d: 69,
e: 70,
f: 71,
g: 72,
h: 73,
i: 74,
j: 75,
k: 76,
l: 77,
m: 78,
n: 79,
o: 80,
p: 81,
q: 82,
r: 83,
s: 84,
t: 85,
u: 86,
v: 87,
w: 88,
x: 89,
y: 90,
z: 91,
'{': 92,
'|': 93,
'}': 94,
'~': 95,
};

Some files were not shown because too many files have changed in this diff Show More