Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/extension/completions-core/vscode-node/extension/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,26 @@ export function isCompletionEnabled(accessor: ServicesAccessor): boolean | undef
return isCompletionEnabledForDocument(accessor, editor.document);
}

// --- Start Positron ---
const PositronInlineCompletionsEnableConfigKey = 'positron.assistant.inlineCompletions.enable';
const PositronInlineCompletionsEnableDefault: { [key: string]: boolean } = { '*': true };

function isPositronCompletionEnabledForLanguage(languageId: string): boolean {
const enabledLanguages = vscode.workspace.getConfiguration().get<{ [key: string]: boolean }>(PositronInlineCompletionsEnableConfigKey) ?? PositronInlineCompletionsEnableDefault;
const enabledLanguagesMap = new Map(Object.entries(enabledLanguages));
if (!enabledLanguagesMap.has('*')) {
enabledLanguagesMap.set('*', false);
}
return enabledLanguagesMap.has(languageId) ? enabledLanguagesMap.get(languageId)! : enabledLanguagesMap.get('*')!;
}
// --- End Positron ---

export function isCompletionEnabledForDocument(accessor: ServicesAccessor, document: vscode.TextDocument): boolean {
// --- Start Positron ---
if (!isPositronCompletionEnabledForLanguage(document.languageId)) {
return false;
}
// --- End Positron ---
return getEnabledConfig(accessor, document.languageId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,21 @@ export class CompletionsCoreContribution extends Disposable {
this._register(autorun(reader => {
const unificationStateValue = unificationState.read(reader);
const configEnabled = configurationService.getExperimentBasedConfigObservable<boolean>(ConfigKey.Internal.InlineEditsEnableGhCompletionsProvider, experimentationService).read(reader);
const extensionUnification = unificationStateValue?.extensionUnification ?? false;
// --- Start Positron ---
// Always enable extension unification for Positron; we do not have
// access to the proprietary GitHub Copilot extension that would
// otherwise provide completions.
//
// const extensionUnification = unificationStateValue?.extensionUnification ?? false;
const extensionUnification = true;
// --- End Positron ---

if (unificationStateValue?.codeUnification || extensionUnification || configEnabled || this._copilotToken.read(reader)?.isNoAuthUser) {
if (unificationStateValue?.codeUnification || extensionUnification || configEnabled || this._copilotToken.read(reader)?.isNoAuthUser || Math.random() > 0) {
const provider = this._getOrCreateProvider();
reader.store.add(languages.registerInlineCompletionItemProvider({ pattern: '**' }, provider, { debounceDelayMs: 0, excludes: ['github.copilot'], groupId: 'completions' }));
// --- Start Positron ---
// Added displayName property for showing in Completion Providers
reader.store.add(languages.registerInlineCompletionItemProvider({ pattern: '**' }, provider, { displayName: 'GitHub Copilot', debounceDelayMs: 0, excludes: ['github.copilot'], groupId: 'completions' }));
// --- End Positron ---
}

void commands.executeCommand('setContext', 'github.copilot.extensionUnification.activated', extensionUnification);
Expand Down
24 changes: 1 addition & 23 deletions src/extension/extension/vscode-node/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import '../../intents/node/allIntents';

// --- Start Positron ---
import * as vscode from 'vscode';
import { getFileBasedAuthSession } from '../../../platform/authentication/vscode-node/fileBasedAuth.js';
// --- End Positron ---

function configureDevPackages() {
Expand All @@ -48,28 +47,7 @@ export function activate(context: ExtensionContext, forceActivation?: boolean) {
return;
}

// Don't perform activation if we have no auth session; the original
// extension has an "installed but not signed in" state, but we don't
// support that in Positron.
const authSession = getFileBasedAuthSession();
if (!authSession) {
// There's no auth session yet, but we don't want to require a restart
// when one is established. Listen for a Copilot auth session to be
// established.
console.log(`[Copilot Chat] No auth session found, extension will not activate until sign-in`);
const api = vscode.extensions.getExtension('positron.positron-assistant')?.exports;
if (api) {
api.onProviderSignIn((provider: string) => {
if (provider === 'copilot') {
console.info('[Copilot Chat] Detected Copilot sign-in, activating extension');
activate(context, forceActivation);
}
});
} else {
console.error('[Copilot Chat] Failed to get Positron API');
}
return;
}
// TODO: Don't activate until we have an auth session
// --- End Positron ---

return baseActivate({
Expand Down
17 changes: 17 additions & 0 deletions src/extension/inlineEdits/common/positronConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2025 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

/**
* Configuration key for Positron inline completions enable setting.
* This has the same format as github.copilot.enable: { [languageId]: boolean }
*/
export const PositronInlineCompletionsEnableConfigKey = 'positron.assistant.inlineCompletions.enable';

/**
* Default value for the Positron inline completions enable setting.
*/
export const PositronInlineCompletionsEnableDefault: { [key: string]: boolean } = {
'*': true,
};
18 changes: 16 additions & 2 deletions src/extension/inlineEdits/vscode-node/inlineCompletionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import { InlineEditLogger } from './parts/inlineEditLogger';
import { IVSCodeObservableDocument } from './parts/vscodeWorkspace';
import { toExternalRange } from './utils/translations';

// --- Start Positron ---
import { PositronInlineCompletionsEnableConfigKey, PositronInlineCompletionsEnableDefault } from '../common/positronConfig';
// --- End Positron ---

const learnMoreAction: Command = {
title: l10n.t('Learn More'),
command: learnMoreCommandId,
Expand Down Expand Up @@ -122,16 +126,18 @@ export class InlineCompletionProviderImpl implements InlineCompletionItemProvide
this._tracer = createTracer(['NES', 'Provider'], (s) => this._logService.trace(s));
this._displayNextEditorNES = this._configurationService.getExperimentBasedConfig(ConfigKey.Internal.UseAlternativeNESNotebookFormat, this._expService);
}

// --- Start Positron ---
// Use Positron's inline completions enable config key instead of Copilot's
// copied from `vscodeWorkspace.ts` `DocumentFilter#_enabledLanguages`
private _isCompletionsEnabled(document: TextDocument): boolean {
const enabledLanguages = this._configurationService.getConfig(ConfigKey.Enable);
const enabledLanguages = this._configurationService.getNonExtensionConfig<{ [key: string]: boolean }>(PositronInlineCompletionsEnableConfigKey) ?? PositronInlineCompletionsEnableDefault;
const enabledLanguagesMap = new Map(Object.entries(enabledLanguages));
if (!enabledLanguagesMap.has('*')) {
enabledLanguagesMap.set('*', false);
}
return enabledLanguagesMap.has(document.languageId) ? enabledLanguagesMap.get(document.languageId)! : enabledLanguagesMap.get('*')!;
}
// --- End Positron ---

public async provideInlineCompletionItems(
document: TextDocument,
Expand All @@ -141,7 +147,15 @@ export class InlineCompletionProviderImpl implements InlineCompletionItemProvide
): Promise<NesCompletionList | undefined> {
const tracer = this._tracer.sub(['provideInlineCompletionItems', shortOpportunityId(context.requestUuid)]);

// --- Start Positron ---
// If inline completions are disabled for this language, don't
// provide any completions.
const isCompletionsEnabled = this._isCompletionsEnabled(document);
if (!isCompletionsEnabled) {
tracer.returns('inline completions disabled for this language');
return undefined;
}
// --- End Positron ---

const unification = this._configurationService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsUnification, this._expService);

Expand Down
12 changes: 11 additions & 1 deletion src/extension/inlineEdits/vscode-node/parts/documentFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService
import { isNotebookCellOrNotebookChatInput } from '../../../../util/common/notebooks';
import { derived } from '../../../../util/vs/base/common/observableInternal';

// --- Start Positron ---
import { PositronInlineCompletionsEnableConfigKey, PositronInlineCompletionsEnableDefault } from '../../common/positronConfig';
// --- End Positron ---

export class DocumentFilter {
private readonly _enabledLanguagesObs;
private readonly _ignoreCompletionsDisablement;
Expand All @@ -17,7 +21,13 @@ export class DocumentFilter {
@IIgnoreService private readonly _ignoreService: IIgnoreService,
@IConfigurationService private readonly _configurationService: IConfigurationService
) {
this._enabledLanguagesObs = this._configurationService.getConfigObservable(ConfigKey.Enable);
// --- Start Positron ---
// Use Positron's inline completions enable config key instead of Copilot's
this._enabledLanguagesObs = this._configurationService.getNonExtensionConfigObservable<{ [key: string]: boolean }>(
PositronInlineCompletionsEnableConfigKey,
PositronInlineCompletionsEnableDefault
);
// --- End Positron ---
this._ignoreCompletionsDisablement = this._configurationService.getConfigObservable(ConfigKey.Internal.InlineEditsIgnoreCompletionsDisablement);
}

Expand Down
13 changes: 0 additions & 13 deletions src/platform/authentication/vscode-node/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ import { AuthPermissionMode, AuthProviderId, ConfigKey, IConfigurationService }
import { GITHUB_SCOPE_ALIGNED, GITHUB_SCOPE_READ_USER, GITHUB_SCOPE_USER_EMAIL, MinimalModeError } from '../common/authentication';
import { mixin } from '../../../util/vs/base/common/objects';

// --- Start Positron ---
import { getFileBasedAuthSession } from './fileBasedAuth';
// --- End Positron ---

export const SESSION_LOGIN_MESSAGE = 'You are not signed in to GitHub. Please sign in to use Copilot.';
// These types are subsets of the "real" types AuthenticationSessionAccountInformation and
// AuthenticationSession. They allow us to use the type system to validate which fields
Expand Down Expand Up @@ -73,15 +69,6 @@ async function getAuthSession(providerId: string, defaultScopes: string[], getSi
* @deprecated use `IAuthenticationService` instead
*/
export function getAnyAuthSession(configurationService: IConfigurationService, options?: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
// --- Start Positron ---
// First, try to get authentication from the file-based GitHub Copilot apps.json
const fileBasedSession = getFileBasedAuthSession();
if (fileBasedSession) {
return Promise.resolve(fileBasedSession);
}

// Fall back to VS Code authentication system
// --- End Positron ---

const providerId = authProviderId(configurationService);

Expand Down
36 changes: 36 additions & 0 deletions src/platform/configuration/common/configurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ export interface IConfigurationService {
*/
getNonExtensionConfig<T>(configKey: string): T | undefined;

// --- Start Positron ---

/**
* Gets an observable for a configuration value that is not in the Copilot namespace.
* @param configKey The fully qualified config key to look up (e.g., 'positron.assistant.inlineCompletions.enable')
* @param defaultValue The default value to use if the config is not set
*/
getNonExtensionConfigObservable<T>(configKey: string, defaultValue: T): IObservable<T>;
// --- End Positron ---

/**
* Sets user configuration for a key in vscode.
*/
Expand Down Expand Up @@ -260,6 +270,29 @@ export abstract class AbstractConfigurationService extends Disposable implements

private observables = new Map<string, IObservable<any>>();

// --- Start Positron ---
public getNonExtensionConfigObservable<T>(configKey: string, defaultValue: T): IObservable<T> {
return this._getNonExtensionObservable(configKey, defaultValue);
}

private _getNonExtensionObservable<T>(configKey: string, defaultValue: T): IObservable<T> {
let observable = this.observables.get(configKey);
if (!observable) {
observable = observableFromEventOpts(
{ debugName: () => `Non-Extension Configuration Key "${configKey}"` },
(handleChange) => this._register(this.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(configKey)) {
handleChange(e);
}
})),
() => this.getNonExtensionConfig(configKey) ?? defaultValue
);
this.observables.set(configKey, observable);
}
return observable;
}
// --- End Positron ---

private _getObservable_$show2FramesUp<T>(key: BaseConfig<T>, getValue: () => T): IObservable<T> {
let observable = this.observables.get(key.id);
if (!observable) {
Expand Down Expand Up @@ -739,6 +772,9 @@ export namespace ConfigKey {
export const Gpt5AlternativePatch = defineExpSetting<boolean>('chat.advanced.gpt5AlternativePatch', false);
}

// --- Start Positron ---
// Note: Not used in Positron, but kept here to avoid breaking changes
// --- End Positron ---
export const Enable = defineSetting<{ [key: string]: boolean }>('enable', {
"*": true,
"plaintext": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ export class InMemoryConfigurationService extends AbstractConfigurationService {

override setConfig<T>(key: BaseConfig<T>, value: T): Promise<void> {
this.overrides.set(key, value);
// --- Start Positron ---
this._onDidChangeConfiguration.fire({ affectsConfiguration: (k) => k === key.fullyQualifiedId });
// --- End Positron ---
return Promise.resolve();
}

setNonExtensionConfig<T>(key: string, value: T): Promise<void> {
this.nonExtensionOverrides.set(key, value);
// --- Start Positron ---
this._onDidChangeConfiguration.fire({ affectsConfiguration: (k) => k === key });
// --- End Positron ---
return Promise.resolve();
}

Expand Down
Loading