Skip to content

Commit

Permalink
Merge branch 'main' into fix-telemetry-info-table
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmaniak authored Nov 15, 2024
2 parents 2034506 + 076f092 commit a941a59
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -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<void> {
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\<name>\AppData\Local\Programs\Microsoft VS Code Insiders\resources\app
// extensionsPath = C:\Users\<name>\AppData\Local\Programs\Microsoft VS Code Insiders\extras\extensions
return URI.file(join(dirname(dirname(this.environmentService.appRoot)), 'extras', 'extensions'));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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)
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.', '<keybinding:repl.execute>'),
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.', '<keybinding:repl.focusLastItemExecuted>'),
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.', '<keybinding:editor.action.accessibleView>'),
localize('replEditor.focusReplInput', 'The Focus Input Editor command{0} will bring the focus back to this editor.', '<keybinding:repl.input.focus>'),
].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.', '<keybinding:notebook.cell.edit>'),
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.', '<keybinding:notebook.cell.quitEdit>'),
localize('replEditor.accessibilityView', 'Run the Open Accessbility View command{0} while navigating the history for an accessible view of the item\'s output.', '<keybinding:editor.action.accessibleView>'),
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.', '<keybinding:repl.input.focus>'),
localize('replEditor.focusInOutput', 'The Focus Output command{0} will set focus on the output when focused on a previously executed item.', '<keybinding:notebook.cell.focusInOutput>'),
localize('replEditor.focusReplInputFromHistory', 'The Focus Input Editor command{0} will move focus to the REPL input box.', '<keybinding:repl.input.focus>'),
localize('replEditor.focusLastItemAdded', 'The Focus Last executed command{0} will move focus to the last executed item in the REPL history.', '<keybinding:repl.focusLastItemExecuted>'),
].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,
);
}

0 comments on commit a941a59

Please sign in to comment.