Skip to content

Commit bc99eae

Browse files
authored
Merge pull request microsoft#254873 from microsoft/copilot/fix-254872
Fix terminal suggest providers default enablement logic
2 parents e31bfca + c34f818 commit bc99eae

File tree

3 files changed

+114
-6
lines changed

3 files changed

+114
-6
lines changed

src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
153153
return this._collectCompletions(providers, shellType, promptValue, cursorPosition, allowFallbackCompletions, capabilities, token, explicitlyInvoked);
154154
}
155155

156-
const providerConfig: { [key: string]: boolean } = this._configurationService.getValue(TerminalSuggestSettingId.Providers);
157-
providers = providers.filter(p => {
158-
const providerId = p.id;
159-
return providerId && providerId in providerConfig && providerConfig[providerId] !== false;
160-
});
156+
providers = this._getEnabledProviders(providers);
161157

162158
if (!providers.length) {
163159
return;
@@ -166,6 +162,14 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
166162
return this._collectCompletions(providers, shellType, promptValue, cursorPosition, allowFallbackCompletions, capabilities, token, explicitlyInvoked);
167163
}
168164

165+
protected _getEnabledProviders(providers: ITerminalCompletionProvider[]): ITerminalCompletionProvider[] {
166+
const providerConfig: { [key: string]: boolean } = this._configurationService.getValue(TerminalSuggestSettingId.Providers);
167+
return providers.filter(p => {
168+
const providerId = p.id;
169+
return providerId && (!(providerId in providerConfig) || providerConfig[providerId] !== false);
170+
});
171+
}
172+
169173
private async _collectCompletions(providers: ITerminalCompletionProvider[], shellType: TerminalShellType | undefined, promptValue: string, cursorPosition: number, allowFallbackCompletions: boolean, capabilities: ITerminalCapabilityStore, token: CancellationToken, explicitlyInvoked?: boolean): Promise<ITerminalCompletion[] | undefined> {
170174
const completionPromises = providers.map(async provider => {
171175
if (provider.shellTypes && shellType && !provider.shellTypes.includes(shellType)) {

src/vs/workbench/contrib/terminalContrib/suggest/common/terminalSuggestConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export interface ITerminalSuggestConfiguration {
5757
providers: {
5858
'terminal-suggest': boolean;
5959
'pwsh-shell-integration': boolean;
60+
[key: string]: boolean;
6061
};
6162
showStatusBar: boolean;
6263
cdPath: 'off' | 'relative' | 'absolute';

src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { URI } from '../../../../../../base/common/uri.js';
77
import { IFileService, IFileStatWithMetadata, IResolveMetadataFileOptions } from '../../../../../../platform/files/common/files.js';
8-
import { TerminalCompletionService, TerminalResourceRequestConfig } from '../../browser/terminalCompletionService.js';
8+
import { TerminalCompletionService, TerminalResourceRequestConfig, type ITerminalCompletionProvider } from '../../browser/terminalCompletionService.js';
99
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js';
1010
import assert, { fail } from 'assert';
1111
import { isWindows, type IProcessEnvironment } from '../../../../../../base/common/platform.js';
@@ -21,6 +21,7 @@ import { count } from '../../../../../../base/common/strings.js';
2121
import { WindowsShellType } from '../../../../../../platform/terminal/common/terminal.js';
2222
import { gitBashToWindowsPath, windowsToGitBashPath } from '../../browser/terminalGitBashHelpers.js';
2323
import { ILogService, NullLogService } from '../../../../../../platform/log/common/log.js';
24+
import { TerminalSuggestSettingId } from '../../common/terminalSuggestConfiguration.js';
2425

2526
const pathSeparator = isWindows ? '\\' : '/';
2627

@@ -770,4 +771,106 @@ suite('TerminalCompletionService', () => {
770771
});
771772

772773
});
774+
775+
suite('Provider Configuration', () => {
776+
// Test class that extends TerminalCompletionService to access protected methods
777+
class TestTerminalCompletionService extends TerminalCompletionService {
778+
public getEnabledProviders(providers: ITerminalCompletionProvider[]): ITerminalCompletionProvider[] {
779+
return super._getEnabledProviders(providers);
780+
}
781+
}
782+
783+
let testTerminalCompletionService: TestTerminalCompletionService;
784+
785+
setup(() => {
786+
testTerminalCompletionService = store.add(instantiationService.createInstance(TestTerminalCompletionService));
787+
});
788+
789+
// Mock provider for testing
790+
function createMockProvider(id: string): ITerminalCompletionProvider {
791+
return {
792+
id,
793+
provideCompletions: async () => [{
794+
label: `completion-from-${id}`,
795+
kind: TerminalCompletionItemKind.Method,
796+
replacementIndex: 0,
797+
replacementLength: 0,
798+
provider: id
799+
}]
800+
};
801+
}
802+
803+
test('should enable providers by default when no configuration exists', () => {
804+
const defaultProvider = createMockProvider('terminal-suggest');
805+
const newProvider = createMockProvider('new-extension-provider');
806+
const providers = [defaultProvider, newProvider];
807+
808+
// Set empty configuration (no provider keys)
809+
configurationService.setUserConfiguration(TerminalSuggestSettingId.Providers, {});
810+
811+
const result = testTerminalCompletionService.getEnabledProviders(providers);
812+
813+
// Both providers should be enabled since they're not explicitly disabled
814+
assert.strictEqual(result.length, 2, 'Should enable both providers by default');
815+
assert.ok(result.includes(defaultProvider), 'Should include default provider');
816+
assert.ok(result.includes(newProvider), 'Should include new provider');
817+
});
818+
819+
test('should disable providers when explicitly set to false', () => {
820+
const provider1 = createMockProvider('provider1');
821+
const provider2 = createMockProvider('provider2');
822+
const providers = [provider1, provider2];
823+
824+
// Disable provider1, leave provider2 unconfigured
825+
configurationService.setUserConfiguration(TerminalSuggestSettingId.Providers, {
826+
'provider1': false
827+
});
828+
829+
const result = testTerminalCompletionService.getEnabledProviders(providers);
830+
831+
// Only provider2 should be enabled
832+
assert.strictEqual(result.length, 1, 'Should enable only one provider');
833+
assert.ok(result.includes(provider2), 'Should include unconfigured provider');
834+
assert.ok(!result.includes(provider1), 'Should not include disabled provider');
835+
});
836+
837+
test('should enable providers when explicitly set to true', () => {
838+
const provider1 = createMockProvider('provider1');
839+
const provider2 = createMockProvider('provider2');
840+
const providers = [provider1, provider2];
841+
842+
// Explicitly enable provider1, leave provider2 unconfigured
843+
configurationService.setUserConfiguration(TerminalSuggestSettingId.Providers, {
844+
'provider1': true
845+
});
846+
847+
const result = testTerminalCompletionService.getEnabledProviders(providers);
848+
849+
// Both providers should be enabled
850+
assert.strictEqual(result.length, 2, 'Should enable both providers');
851+
assert.ok(result.includes(provider1), 'Should include explicitly enabled provider');
852+
assert.ok(result.includes(provider2), 'Should include unconfigured provider');
853+
});
854+
855+
test('should handle mixed configuration correctly', () => {
856+
const provider1 = createMockProvider('provider1');
857+
const provider2 = createMockProvider('provider2');
858+
const provider3 = createMockProvider('provider3');
859+
const providers = [provider1, provider2, provider3];
860+
861+
// Mixed configuration: enable provider1, disable provider2, leave provider3 unconfigured
862+
configurationService.setUserConfiguration(TerminalSuggestSettingId.Providers, {
863+
'provider1': true,
864+
'provider2': false
865+
});
866+
867+
const result = testTerminalCompletionService.getEnabledProviders(providers);
868+
869+
// provider1 and provider3 should be enabled, provider2 should be disabled
870+
assert.strictEqual(result.length, 2, 'Should enable two providers');
871+
assert.ok(result.includes(provider1), 'Should include explicitly enabled provider');
872+
assert.ok(result.includes(provider3), 'Should include unconfigured provider');
873+
assert.ok(!result.includes(provider2), 'Should not include disabled provider');
874+
});
875+
});
773876
});

0 commit comments

Comments
 (0)