diff --git a/news/1 Enhancements/18710.md b/news/1 Enhancements/18710.md new file mode 100644 index 000000000000..05372f36d9fb --- /dev/null +++ b/news/1 Enhancements/18710.md @@ -0,0 +1 @@ +Move interpreter info status bar item to the right. diff --git a/package.json b/package.json index 030f283c0ac0..7b9c5c7c943b 100644 --- a/package.json +++ b/package.json @@ -537,10 +537,7 @@ "items": { "enum": [ "All", - "pythonDeprecatePythonPath", - "pythonSurveyNotification", - "pythonInterpreterInfoPinned", - "pythonInterpreterInfoUnpinned" + "pythonSurveyNotification" ] }, "scope": "machine", @@ -552,10 +549,7 @@ "items": { "enum": [ "All", - "pythonDeprecatePythonPath", - "pythonSurveyNotification", - "pythonInterpreterInfoPinned", - "pythonInterpreterInfoUnpinned" + "pythonSurveyNotification" ] }, "scope": "machine", diff --git a/src/client/common/experiments/groups.ts b/src/client/common/experiments/groups.ts index 37359a2aea9f..7f2b9f74cef5 100644 --- a/src/client/common/experiments/groups.ts +++ b/src/client/common/experiments/groups.ts @@ -2,7 +2,3 @@ export enum ShowExtensionSurveyPrompt { experiment = 'pythonSurveyNotification', } -export enum InterpreterStatusBarPosition { - Pinned = 'pythonInterpreterInfoPinned', - Unpinned = 'pythonInterpreterInfoUnpinned', -} diff --git a/src/client/interpreter/display/index.ts b/src/client/interpreter/display/index.ts index dfdea218a42c..b784b693eba3 100644 --- a/src/client/interpreter/display/index.ts +++ b/src/client/interpreter/display/index.ts @@ -3,9 +3,8 @@ import { Disposable, LanguageStatusItem, LanguageStatusSeverity, StatusBarAlignm import { IExtensionSingleActivationService } from '../../activation/types'; import { IApplicationShell, IWorkspaceService } from '../../common/application/types'; import { Commands, PYTHON_LANGUAGE } from '../../common/constants'; -import { InterpreterStatusBarPosition } from '../../common/experiments/groups'; import '../../common/extensions'; -import { IDisposableRegistry, IExperimentService, IPathUtils, Resource } from '../../common/types'; +import { IDisposableRegistry, IPathUtils, Resource } from '../../common/types'; import { InterpreterQuickPickList, Interpreters } from '../../common/utils/localize'; import { IServiceContainer } from '../../ioc/types'; import { traceLog } from '../../logging'; @@ -29,6 +28,7 @@ export class InterpreterDisplay implements IInterpreterDisplay, IExtensionSingle virtualWorkspace: true, }; private statusBar: StatusBarItem | undefined; + private useLanguageStatus = false; private languageStatus: LanguageStatusItem | undefined; private readonly helper: IInterpreterHelper; private readonly workspaceService: IWorkspaceService; @@ -40,7 +40,6 @@ export class InterpreterDisplay implements IInterpreterDisplay, IExtensionSingle private statusBarCanBeDisplayed?: boolean; private visibilityFilters: IInterpreterStatusbarVisibilityFilter[] = []; private disposableRegistry: Disposable[]; - private experiments: IExperimentService; constructor(@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer) { this.helper = serviceContainer.get(IInterpreterHelper); @@ -55,12 +54,11 @@ export class InterpreterDisplay implements IInterpreterDisplay, IExtensionSingle this, this.disposableRegistry, ); - this.experiments = this.serviceContainer.get(IExperimentService); } public async activate(): Promise { const application = this.serviceContainer.get(IApplicationShell); - if (this.experiments.inExperimentSync(InterpreterStatusBarPosition.Unpinned)) { + if (this.useLanguageStatus) { this.languageStatus = application.createLanguageStatusItem('python.selectedInterpreter', { language: PYTHON_LANGUAGE, }); @@ -71,10 +69,7 @@ export class InterpreterDisplay implements IInterpreterDisplay, IExtensionSingle }; this.disposableRegistry.push(this.languageStatus); } else { - let [alignment, priority] = [StatusBarAlignment.Left, 100]; - if (this.experiments.inExperimentSync(InterpreterStatusBarPosition.Pinned)) { - [alignment, priority] = [StatusBarAlignment.Right, STATUS_BAR_ITEM_PRIORITY]; - } + const [alignment, priority] = [StatusBarAlignment.Right, STATUS_BAR_ITEM_PRIORITY]; this.statusBar = application.createStatusBarItem(alignment, priority); this.statusBar.command = Commands.Set_Interpreter; this.disposableRegistry.push(this.statusBar); @@ -120,9 +115,7 @@ export class InterpreterDisplay implements IInterpreterDisplay, IExtensionSingle this.interpreterPath = interpreter.path; } let text = interpreter.detailedDisplayName; - if (this.experiments.inExperimentSync(InterpreterStatusBarPosition.Pinned)) { - text = text?.startsWith('Python') ? text?.substring('Python'.length)?.trim() : text; - } + text = text?.startsWith('Python') ? text?.substring('Python'.length)?.trim() : text; this.statusBar.text = text!; this.currentlySelectedInterpreterPath = interpreter.path; } else { diff --git a/src/client/interpreter/interpreterService.ts b/src/client/interpreter/interpreterService.ts index 90aa1a613604..90c3096e40e8 100644 --- a/src/client/interpreter/interpreterService.ts +++ b/src/client/interpreter/interpreterService.ts @@ -4,12 +4,7 @@ import * as pathUtils from 'path'; import { Disposable, Event, EventEmitter, Uri } from 'vscode'; import '../common/extensions'; import { IDocumentManager } from '../common/application/types'; -import { - IConfigurationService, - IDisposableRegistry, - IExperimentService, - IInterpreterPathService, -} from '../common/types'; +import { IConfigurationService, IDisposableRegistry, IInterpreterPathService } from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { PythonEnvironment } from '../pythonEnvironments/info'; import { @@ -22,7 +17,6 @@ import { import { PythonLocatorQuery } from '../pythonEnvironments/base/locator'; import { traceError } from '../logging'; import { PYTHON_LANGUAGE } from '../common/constants'; -import { InterpreterStatusBarPosition } from '../common/experiments/groups'; import { reportActiveInterpreterChanged } from '../proposedApi'; import { IPythonExecutionFactory } from '../common/process/types'; @@ -100,13 +94,14 @@ export class InterpreterService implements Disposable, IInterpreterService { public readonly changed = this.interpreterVisibilityEmitter.event; get hidden() { - return this.docManager.activeTextEditor?.document.languageId !== PYTHON_LANGUAGE; + const document = this.docManager.activeTextEditor?.document; + if (document?.fileName.endsWith('settings.json')) { + return false; + } + return document?.languageId !== PYTHON_LANGUAGE; } })(documentManager); - const experiments = this.serviceContainer.get(IExperimentService); - if (experiments.inExperimentSync(InterpreterStatusBarPosition.Pinned)) { - interpreterDisplay.registerVisibilityFilter(filter); - } + interpreterDisplay.registerVisibilityFilter(filter); disposables.push( this.onDidChangeInterpreters((e): void => { const interpreter = e.old ?? e.new; diff --git a/src/test/interpreters/display.unit.test.ts b/src/test/interpreters/display.unit.test.ts index 9561aad47836..bae608384ed3 100644 --- a/src/test/interpreters/display.unit.test.ts +++ b/src/test/interpreters/display.unit.test.ts @@ -17,9 +17,8 @@ import { import { IExtensionSingleActivationService } from '../../client/activation/types'; import { IApplicationShell, IWorkspaceService } from '../../client/common/application/types'; import { Commands, PYTHON_LANGUAGE } from '../../client/common/constants'; -import { InterpreterStatusBarPosition } from '../../client/common/experiments/groups'; import { IFileSystem } from '../../client/common/platform/types'; -import { IDisposableRegistry, IExperimentService, IPathUtils, ReadWrite } from '../../client/common/types'; +import { IDisposableRegistry, IPathUtils, ReadWrite } from '../../client/common/types'; import { InterpreterQuickPickList, Interpreters } from '../../client/common/utils/localize'; import { Architecture } from '../../client/common/utils/platform'; import { @@ -55,7 +54,6 @@ suite('Interpreters Display', () => { let statusBar: TypeMoq.IMock; let interpreterDisplay: IInterpreterDisplay & IExtensionSingleActivationService; let interpreterHelper: TypeMoq.IMock; - let experiments: TypeMoq.IMock; let pathUtils: TypeMoq.IMock; let languageStatusItem: TypeMoq.IMock; let traceLogStub: sinon.SinonStub; @@ -65,17 +63,11 @@ suite('Interpreters Display', () => { filters.forEach((f) => interpreterDisplay.registerVisibilityFilter(f)); } - async function setupMocks(inExperiment: InterpreterStatusBarPosition | undefined) { + async function setupMocks(useLanguageStatus: boolean) { serviceContainer = TypeMoq.Mock.ofType(); workspaceService = TypeMoq.Mock.ofType(); applicationShell = TypeMoq.Mock.ofType(); interpreterService = TypeMoq.Mock.ofType(); - experiments = TypeMoq.Mock.ofType(); - if (inExperiment) { - experiments.setup((e) => e.inExperimentSync(inExperiment)).returns(() => true); - } else { - experiments.setup((e) => e.inExperimentSync(TypeMoq.It.isAny())).returns(() => false); - } fileSystem = TypeMoq.Mock.ofType(); interpreterHelper = TypeMoq.Mock.ofType(); disposableRegistry = []; @@ -94,29 +86,22 @@ suite('Interpreters Display', () => { serviceContainer .setup((c) => c.get(TypeMoq.It.isValue(IInterpreterService))) .returns(() => interpreterService.object); - serviceContainer.setup((c) => c.get(TypeMoq.It.isValue(IExperimentService))).returns(() => experiments.object); serviceContainer.setup((c) => c.get(TypeMoq.It.isValue(IFileSystem))).returns(() => fileSystem.object); serviceContainer.setup((c) => c.get(TypeMoq.It.isValue(IDisposableRegistry))).returns(() => disposableRegistry); serviceContainer .setup((c) => c.get(TypeMoq.It.isValue(IInterpreterHelper))) .returns(() => interpreterHelper.object); serviceContainer.setup((c) => c.get(TypeMoq.It.isValue(IPathUtils))).returns(() => pathUtils.object); - if (inExperiment === InterpreterStatusBarPosition.Pinned) { + if (!useLanguageStatus) { applicationShell .setup((a) => a.createStatusBarItem(TypeMoq.It.isValue(StatusBarAlignment.Right), TypeMoq.It.isAny())) .returns(() => statusBar.object); - } else if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + } else { applicationShell .setup((a) => a.createLanguageStatusItem(TypeMoq.It.isAny(), TypeMoq.It.isValue({ language: PYTHON_LANGUAGE })), ) .returns(() => languageStatusItem.object); - } else { - applicationShell - .setup((a) => - a.createStatusBarItem(TypeMoq.It.isValue(StatusBarAlignment.Left), TypeMoq.It.isValue(100)), - ) - .returns(() => statusBar.object); } pathUtils.setup((p) => p.getDisplayName(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((p) => p); await createInterpreterDisplay(); @@ -133,17 +118,17 @@ suite('Interpreters Display', () => { workspaceService.setup((w) => w.getWorkspaceFolder(TypeMoq.It.isValue(resource))).returns(() => undefined); } } - [InterpreterStatusBarPosition.Unpinned, InterpreterStatusBarPosition.Pinned, undefined].forEach((inExperiment) => { - suite(`When ${inExperiment ? `in experiment ${inExperiment}` : 'not in experiment'}`, () => { + [false].forEach((useLanguageStatus) => { + suite(`When ${useLanguageStatus ? `using language status` : 'using status bar'}`, () => { setup(async () => { - setupMocks(inExperiment); + setupMocks(useLanguageStatus); }); teardown(() => { sinon.restore(); }); test('Statusbar must be created and have command name initialized', () => { - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { languageStatusItem.verify( (s) => (s.severity = TypeMoq.It.isValue(LanguageStatusSeverity.Information)), TypeMoq.Times.once(), @@ -185,7 +170,7 @@ suite('Interpreters Display', () => { await interpreterDisplay.refresh(resource); - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { languageStatusItem.verify( (s) => (s.text = TypeMoq.It.isValue(activeInterpreter.detailedDisplayName)!), TypeMoq.Times.once(), @@ -233,7 +218,7 @@ suite('Interpreters Display', () => { const pythonPath = path.join('user', 'development', 'env', 'bin', 'python'); const workspaceFolder = Uri.file('workspace'); const displayName = 'Python 3.10.1'; - const expectedDisplayName = inExperiment ? '3.10.1' : 'Python 3.10.1'; + const expectedDisplayName = '3.10.1'; setupWorkspaceFolder(resource, workspaceFolder); const pythonInterpreter: PythonEnvironment = ({ @@ -245,7 +230,7 @@ suite('Interpreters Display', () => { .returns(() => Promise.resolve(pythonInterpreter)); await interpreterDisplay.refresh(resource); - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { languageStatusItem.verify( (s) => (s.detail = TypeMoq.It.isValue(pythonPath)), TypeMoq.Times.atLeastOnce(), @@ -280,7 +265,7 @@ suite('Interpreters Display', () => { await interpreterDisplay.refresh(resource); - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { languageStatusItem.verify( (s) => (s.text = TypeMoq.It.isValue('$(alert) No Interpreter Selected')), TypeMoq.Times.once(), @@ -320,7 +305,7 @@ suite('Interpreters Display', () => { interpreterHelper.verifyAll(); interpreterService.verifyAll(); - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { languageStatusItem.verify( (s) => (s.text = TypeMoq.It.isValue(activeInterpreter.detailedDisplayName)!), TypeMoq.Times.once(), @@ -340,7 +325,7 @@ suite('Interpreters Display', () => { suite('Visibility', () => { const resource = Uri.file('x'); suiteSetup(function () { - if (inExperiment === InterpreterStatusBarPosition.Unpinned) { + if (useLanguageStatus) { return this.skip(); } }); diff --git a/src/test/interpreters/interpreterService.unit.test.ts b/src/test/interpreters/interpreterService.unit.test.ts index d20acd6b2991..bcf3af9613a8 100644 --- a/src/test/interpreters/interpreterService.unit.test.ts +++ b/src/test/interpreters/interpreterService.unit.test.ts @@ -11,7 +11,6 @@ import * as TypeMoq from 'typemoq'; import * as sinon from 'sinon'; import { ConfigurationTarget, Disposable, TextDocument, TextEditor, Uri, WorkspaceConfiguration } from 'vscode'; import { IDocumentManager, IWorkspaceService } from '../../client/common/application/types'; -import { InterpreterStatusBarPosition } from '../../client/common/experiments/groups'; import { IFileSystem } from '../../client/common/platform/types'; import { IPythonExecutionFactory, IPythonExecutionService } from '../../client/common/process/types'; import { @@ -78,7 +77,6 @@ suite('Interpreters service', () => { pythonExecutionService = TypeMoq.Mock.ofType(); configService = TypeMoq.Mock.ofType(); experiments = TypeMoq.Mock.ofType(); - experiments.setup((e) => e.inExperimentSync(InterpreterStatusBarPosition.Pinned)).returns(() => false); pythonSettings = TypeMoq.Mock.ofType(); pythonSettings.setup((s) => s.pythonPath).returns(() => PYTHON_PATH);