From 53ab97b1033b92248b3c6f2ad3d0cd9dd49637b2 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 15 Nov 2024 14:57:51 -0800 Subject: [PATCH 1/2] separate help menus for REPL input and history (#233955) separate help menus for repl input and history --- .../replNotebook/browser/repl.contribution.ts | 5 +- .../browser/replEditorAccessibilityHelp.ts | 61 ++++++++++++------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts b/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts index 77f57e10fed93..d1fc57b9d4bc5 100644 --- a/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts +++ b/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts @@ -51,7 +51,7 @@ import { NotebookEditorInputOptions } from '../../notebook/common/notebookEditor import { INotebookEditorModelResolverService } from '../../notebook/common/notebookEditorModelResolverService.js'; import { INotebookService } from '../../notebook/common/notebookService.js'; import { isReplEditorControl, ReplEditor, ReplEditorControl } from './replEditor.js'; -import { ReplEditorAccessibilityHelp } from './replEditorAccessibilityHelp.js'; +import { ReplEditorHistoryAccessibilityHelp, ReplEditorInputAccessibilityHelp } from './replEditorAccessibilityHelp.js'; import { ReplEditorInput } from './replEditorInput.js'; type SerializedNotebookEditorData = { resource: URI; preferredResource: URI; viewType: string; options?: NotebookEditorInputOptions; label?: string }; @@ -224,7 +224,8 @@ class ReplWindowWorkingCopyEditorHandler extends Disposable implements IWorkbenc registerWorkbenchContribution2(ReplWindowWorkingCopyEditorHandler.ID, ReplWindowWorkingCopyEditorHandler, WorkbenchPhase.BlockRestore); registerWorkbenchContribution2(ReplDocumentContribution.ID, ReplDocumentContribution, WorkbenchPhase.BlockRestore); -AccessibleViewRegistry.register(new ReplEditorAccessibilityHelp()); +AccessibleViewRegistry.register(new ReplEditorInputAccessibilityHelp()); +AccessibleViewRegistry.register(new ReplEditorHistoryAccessibilityHelp()); registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/replNotebook/browser/replEditorAccessibilityHelp.ts b/src/vs/workbench/contrib/replNotebook/browser/replEditorAccessibilityHelp.ts index 35cab6df38d49..b88e9f6d3554a 100644 --- a/src/vs/workbench/contrib/replNotebook/browser/replEditorAccessibilityHelp.ts +++ b/src/vs/workbench/contrib/replNotebook/browser/replEditorAccessibilityHelp.ts @@ -4,53 +4,70 @@ *--------------------------------------------------------------------------------------------*/ import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { IAccessibleViewImplentation } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js'; +import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { localize } from '../../../../nls.js'; -import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { AccessibleViewProviderId, AccessibleViewType, AccessibleContentProvider } from '../../../../platform/accessibility/browser/accessibleView.js'; import { AccessibilityVerbositySettingId } from '../../accessibility/browser/accessibilityConfiguration.js'; -import { IEditorService } from '../../../services/editor/common/editorService.js'; -import { IVisibleEditorPane } from '../../../common/editor.js'; import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; -import { IS_COMPOSITE_NOTEBOOK } from '../../notebook/common/notebookContextKeys.js'; +import { IS_COMPOSITE_NOTEBOOK, NOTEBOOK_CELL_LIST_FOCUSED } from '../../notebook/common/notebookContextKeys.js'; -export class ReplEditorAccessibilityHelp implements IAccessibleViewImplentation { +export class ReplEditorInputAccessibilityHelp implements IAccessibleViewImplentation { readonly priority = 105; - readonly name = 'REPL Editor'; - readonly when = IS_COMPOSITE_NOTEBOOK; + readonly name = 'REPL Editor Input'; + readonly when = ContextKeyExpr.and(IS_COMPOSITE_NOTEBOOK, NOTEBOOK_CELL_LIST_FOCUSED.negate()); readonly type: AccessibleViewType = AccessibleViewType.Help; getProvider(accessor: ServicesAccessor) { - const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor() - || accessor.get(ICodeEditorService).getFocusedCodeEditor() - || accessor.get(IEditorService).activeEditorPane; - - if (!activeEditor) { - return; - } - return getAccessibilityHelpProvider(accessor, activeEditor); + return getAccessibilityHelpProvider(accessor.get(ICodeEditorService), getAccessibilityInputHelpText()); } } -function getAccessibilityHelpText(): string { +function getAccessibilityInputHelpText(): string { return [ - localize('replEditor.overview', 'You are in a REPL Editor which contains in input box to evaluate expressions and a list of previously executed expressions and their output.'), + localize('replEditor.inputOverview', 'You are in a REPL Editor Input box which will accept code to be executed in the REPL.'), localize('replEditor.execute', 'The Execute command{0} will evaluate the expression in the input box.', ''), localize('replEditor.configReadExecution', 'The setting `accessibility.replEditor.readLastExecutionOutput` controls if output will be automatically read when execution completes.'), localize('replEditor.autoFocusRepl', 'The setting `accessibility.replEditor.autoFocusReplExecution` controls if focus will automatically move to the REPL after executing code.'), localize('replEditor.focusLastItemAdded', 'The Focus Last executed command{0} will move focus to the last executed item in the REPL history.', ''), + localize('replEditor.inputAccessibilityView', 'When you run the Open Accessbility View command{0} from this input box, the output from the last execution will be shown in the accessibility view.', ''), + localize('replEditor.focusReplInput', 'The Focus Input Editor command{0} will bring the focus back to this editor.', ''), + ].join('\n'); +} + +export class ReplEditorHistoryAccessibilityHelp implements IAccessibleViewImplentation { + readonly priority = 105; + readonly name = 'REPL Editor History'; + readonly when = ContextKeyExpr.and(IS_COMPOSITE_NOTEBOOK, NOTEBOOK_CELL_LIST_FOCUSED); + readonly type: AccessibleViewType = AccessibleViewType.Help; + getProvider(accessor: ServicesAccessor) { + return getAccessibilityHelpProvider(accessor.get(ICodeEditorService), getAccessibilityHistoryHelpText()); + } +} + +function getAccessibilityHistoryHelpText(): string { + return [ + localize('replEditor.historyOverview', 'You are in a REPL History which is a list of cells that have been executed in the REPL. Each cell has an input, an output, and the cell container.'), + localize('replEditor.focusCellEditor', 'The Edit Cell command{0} will move focus to the read-only editor for the input of the cell.', ''), + localize('replEditor.cellNavigation', 'The Quit Edit command{0} will move focus to the cell container, where the up and down arrows will also move focus between cells in the history.', ''), localize('replEditor.accessibilityView', 'Run the Open Accessbility View command{0} while navigating the history for an accessible view of the item\'s output.', ''), - localize('replEditor.cellNavigation', 'The up and down arrows will also move focus between previously executed items while focused on the REPL history.'), - localize('replEditor.focusReplInput', 'The Focus Input Editor command{0} will move focus to the REPL input box.', ''), localize('replEditor.focusInOutput', 'The Focus Output command{0} will set focus on the output when focused on a previously executed item.', ''), + localize('replEditor.focusReplInputFromHistory', 'The Focus Input Editor command{0} will move focus to the REPL input box.', ''), + localize('replEditor.focusLastItemAdded', 'The Focus Last executed command{0} will move focus to the last executed item in the REPL history.', ''), ].join('\n'); } -function getAccessibilityHelpProvider(accessor: ServicesAccessor, editor: ICodeEditor | IVisibleEditorPane) { - const helpText = getAccessibilityHelpText(); +function getAccessibilityHelpProvider(editorService: ICodeEditorService, helpText: string) { + const activeEditor = editorService.getActiveCodeEditor() + || editorService.getFocusedCodeEditor(); + + if (!activeEditor) { + return; + } + return new AccessibleContentProvider( AccessibleViewProviderId.ReplEditor, { type: AccessibleViewType.Help }, () => helpText, - () => editor.focus(), + () => activeEditor.focus(), AccessibilityVerbositySettingId.ReplEditor, ); } From 076f0926a09810d99d9f2afa25d87f4df3693d0e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sat, 16 Nov 2024 00:06:58 +0100 Subject: [PATCH 2/2] Support installing default extensions on first startup (#233957) Support installing default extensions on first startup #232990 --- .../contrib/defaultExtensionsInitializer.ts | 78 +++++++++++++++++++ .../sharedProcess/sharedProcessMain.ts | 4 +- .../node/extensionManagementService.ts | 2 +- 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/vs/code/electron-utility/sharedProcess/contrib/defaultExtensionsInitializer.ts diff --git a/src/vs/code/electron-utility/sharedProcess/contrib/defaultExtensionsInitializer.ts b/src/vs/code/electron-utility/sharedProcess/contrib/defaultExtensionsInitializer.ts new file mode 100644 index 0000000000000..e03ae6ba2715d --- /dev/null +++ b/src/vs/code/electron-utility/sharedProcess/contrib/defaultExtensionsInitializer.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { dirname, join } from 'path'; +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { isWindows } from '../../../../base/common/platform.js'; +import { URI } from '../../../../base/common/uri.js'; +import { INativeEnvironmentService } from '../../../../platform/environment/common/environment.js'; +import { INativeServerExtensionManagementService } from '../../../../platform/extensionManagement/node/extensionManagementService.js'; +import { ILogService } from '../../../../platform/log/common/log.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; +import { FileOperationResult, IFileService, IFileStat, toFileOperationResult } from '../../../../platform/files/common/files.js'; +import { getErrorMessage } from '../../../../base/common/errors.js'; + +const defaultExtensionsInitStatusKey = 'initializing-default-extensions'; + +export class DefaultExtensionsInitializer extends Disposable { + constructor( + @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService, + @INativeServerExtensionManagementService private readonly extensionManagementService: INativeServerExtensionManagementService, + @IStorageService storageService: IStorageService, + @IFileService private readonly fileService: IFileService, + @ILogService private readonly logService: ILogService, + ) { + super(); + + if (isWindows && storageService.getBoolean(defaultExtensionsInitStatusKey, StorageScope.APPLICATION, true)) { + storageService.store(defaultExtensionsInitStatusKey, true, StorageScope.APPLICATION, StorageTarget.MACHINE); + this.initializeDefaultExtensions().then(() => storageService.store(defaultExtensionsInitStatusKey, false, StorageScope.APPLICATION, StorageTarget.MACHINE)); + } + } + + private async initializeDefaultExtensions(): Promise { + const extensionsLocation = this.getDefaultExtensionVSIXsLocation(); + let stat: IFileStat; + try { + stat = await this.fileService.resolve(extensionsLocation); + if (!stat.children) { + this.logService.debug('There are no default extensions to initialize', extensionsLocation.toString()); + return; + } + } catch (error) { + if (toFileOperationResult(error) === FileOperationResult.FILE_NOT_FOUND) { + this.logService.debug('There are no default extensions to initialize', extensionsLocation.toString()); + return; + } + this.logService.error('Error initializing extensions', error); + return; + } + + const vsixs = stat.children.filter(child => child.name.endsWith('.vsix')); + if (vsixs.length === 0) { + this.logService.debug('There are no default extensions to initialize', extensionsLocation.toString()); + return; + } + + this.logService.info('Initializing default extensions', extensionsLocation.toString()); + await Promise.all(vsixs.map(async vsix => { + this.logService.info('Installing default extension', vsix.resource.toString()); + try { + await this.extensionManagementService.install(vsix.resource, { donotIncludePackAndDependencies: true, keepExisting: false }); + this.logService.info('Default extension installed', vsix.resource.toString()); + } catch (error) { + this.logService.error('Error installing default extension', vsix.resource.toString(), getErrorMessage(error)); + } + })); + this.logService.info('Default extensions initialized', extensionsLocation.toString()); + } + + private getDefaultExtensionVSIXsLocation(): URI { + // appRoot = C:\Users\\AppData\Local\Programs\Microsoft VS Code Insiders\resources\app + // extensionsPath = C:\Users\\AppData\Local\Programs\Microsoft VS Code Insiders\extras\extensions + return URI.file(join(dirname(dirname(this.environmentService.appRoot)), 'extras', 'extensions')); + } + +} diff --git a/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts index 2a99598a73de7..00a0b29125adb 100644 --- a/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts @@ -118,6 +118,7 @@ import { getOSReleaseInfo } from '../../../base/node/osReleaseInfo.js'; import { getDesktopEnvironment } from '../../../base/common/desktopEnvironmentInfo.js'; import { getCodeDisplayProtocol, getDisplayProtocol } from '../../../base/node/osDisplayProtocolInfo.js'; import { RequestService } from '../../../platform/request/electron-utility/requestService.js'; +import { DefaultExtensionsInitializer } from './contrib/defaultExtensionsInitializer.js'; class SharedProcessMain extends Disposable implements IClientConnectionFilter { @@ -187,7 +188,8 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { instantiationService.createInstance(LogsDataCleaner), instantiationService.createInstance(LocalizationsUpdater), instantiationService.createInstance(ExtensionsContributions), - instantiationService.createInstance(UserDataProfilesCleaner) + instantiationService.createInstance(UserDataProfilesCleaner), + instantiationService.createInstance(DefaultExtensionsInitializer) )); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index ad7d55b3b85dd..585272ac91d1b 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -409,7 +409,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi pinned: options.installGivenVersion ? true : !!options.pinned, source: 'vsix', }, - options.keepExisting ?? true, + isBoolean(options.keepExisting) ? !options.keepExisting : true, token); return { local }; }