Skip to content

Commit 7d238f4

Browse files
authored
Add 'open with' to the explorer context menu (microsoft#95805)
This change primarly adds a new `Open with...` entry to the explorer context menu. To do this however, I had to make a few other changes: - Add a new explorer context key for availible editors - Moved the editor select prompt into a new function called `openEditorWith` - Use `openEditorWith` for the new `open with` explorer command as well as for the `reopen with` command
1 parent 8f41818 commit 7d238f4

13 files changed

Lines changed: 213 additions & 130 deletions

File tree

extensions/markdown-language-features/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@
312312
"customEditors": [
313313
{
314314
"viewType": "vscode.markdown.preview.editor",
315-
"displayName": "(Experimental) VS Code Markdown Preview",
315+
"displayName": "Markdown Preview (Experimental)",
316316
"priority": "option",
317317
"selector": [
318318
{

src/vs/workbench/api/browser/mainThreadEditors.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContex
2424
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
2525
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
2626
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
27-
import { DEFAULT_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
27+
import { openEditorWith } from 'vs/workbench/contrib/files/common/openWith';
28+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
29+
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
2830

2931
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
3032

@@ -296,26 +298,17 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
296298

297299
CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAccessor, args: [URI, string, ITextEditorOptions | undefined, EditorViewColumn | undefined]) => {
298300
const editorService = accessor.get(IEditorService);
299-
const editorGroupService = accessor.get(IEditorGroupsService);
301+
const editorGroupsService = accessor.get(IEditorGroupsService);
302+
const configurationService = accessor.get(IConfigurationService);
303+
const quickInputService = accessor.get(IQuickInputService);
300304

301305
const [resource, id, options, position] = args;
302306

303-
const group = editorGroupService.getGroup(viewColumnToEditorGroup(editorGroupService, position)) ?? editorGroupService.activeGroup;
307+
const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, position)) ?? editorGroupsService.activeGroup;
304308
const textOptions = options ? { ...options, ignoreOverrides: true } : { ignoreOverrides: true };
305309

306-
const fileEditorInput = editorService.createEditorInput({ resource, forceFile: true });
307-
if (id === DEFAULT_EDITOR_ID) {
308-
return editorService.openEditor(fileEditorInput, textOptions, position);
309-
}
310-
311-
const editors = editorService.getEditorOverrides(fileEditorInput, undefined, group);
312-
for (const [handler, data] of editors) {
313-
if (data.id === id) {
314-
return handler.open(fileEditorInput, options, group, id);
315-
}
316-
}
317-
318-
return undefined;
310+
const input = editorService.createEditorInput({ resource });
311+
return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService);
319312
});
320313

321314

src/vs/workbench/browser/contextkeys.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Event } from 'vs/base/common/event';
77
import { Disposable } from 'vs/base/common/lifecycle';
88
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
99
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys';
10-
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsReadonlyContext, EditorAreaVisibleContext, DirtyWorkingCopiesContext, ActiveEditorAvailableEditorsContext } from 'vs/workbench/common/editor';
10+
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsReadonlyContext, EditorAreaVisibleContext, DirtyWorkingCopiesContext, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/editor';
1111
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
1212
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
1313
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -41,7 +41,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
4141

4242
private activeEditorContext: IContextKey<string | null>;
4343
private activeEditorIsReadonly: IContextKey<boolean>;
44-
private activeEditorAvailableEditors: IContextKey<string>;
44+
private activeEditorAvailableEditorIds: IContextKey<string>;
4545

4646
private activeEditorGroupEmpty: IContextKey<boolean>;
4747
private activeEditorGroupIndex: IContextKey<number>;
@@ -92,7 +92,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
9292
// Editors
9393
this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
9494
this.activeEditorIsReadonly = ActiveEditorIsReadonlyContext.bindTo(this.contextKeyService);
95-
this.activeEditorAvailableEditors = ActiveEditorAvailableEditorsContext.bindTo(this.contextKeyService);
95+
this.activeEditorAvailableEditorIds = ActiveEditorAvailableEditorIdsContext.bindTo(this.contextKeyService);
9696
this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
9797
this.textCompareEditorVisibleContext = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
9898
this.textCompareEditorActiveContext = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
@@ -211,11 +211,11 @@ export class WorkbenchContextKeysHandler extends Disposable {
211211
this.activeEditorIsReadonly.set(activeEditorPane.input.isReadonly());
212212

213213
const editors = this.editorService.getEditorOverrides(activeEditorPane.input, undefined, activeGroup);
214-
this.activeEditorAvailableEditors.set(editors.map(([_, entry]) => entry.id).join(','));
214+
this.activeEditorAvailableEditorIds.set(editors.map(([_, entry]) => entry.id).join(','));
215215
} else {
216216
this.activeEditorContext.reset();
217217
this.activeEditorIsReadonly.reset();
218-
this.activeEditorAvailableEditors.reset();
218+
this.activeEditorAvailableEditorIds.reset();
219219
}
220220
}
221221

src/vs/workbench/common/editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/
3232
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false);
3333
export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null);
3434
export const ActiveEditorIsReadonlyContext = new RawContextKey<boolean>('activeEditorIsReadonly', false);
35-
export const ActiveEditorAvailableEditorsContext = new RawContextKey<string>('availableEditors', '');
35+
export const ActiveEditorAvailableEditorIdsContext = new RawContextKey<string>('activeEditorAvailableEditorIds', '');
3636
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
3737
export const EditorPinnedContext = new RawContextKey<boolean>('editorPinned', false);
3838
export const EditorGroupActiveEditorDirtyContext = new RawContextKey<boolean>('groupActiveEditorDirty', false);

src/vs/workbench/contrib/customEditor/browser/customEditors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { CONTEXT_CUSTOM_EDITORS, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, Cust
2727
import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager';
2828
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
2929
import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench/contrib/webview/browser/webview';
30-
import { CustomEditorAssociation, CustomEditorsAssociations, customEditorsAssociationsSettingId } from 'vs/workbench/services/editor/browser/editorAssociationsSetting';
30+
import { CustomEditorAssociation, CustomEditorsAssociations, customEditorsAssociationsSettingId } from 'vs/workbench/services/editor/common/editorAssociationsSetting';
3131
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
3232
import { ICustomEditorInfo, ICustomEditorViewTypesHandler, IEditorService, IOpenEditorOverride, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService';
3333
import { ContributedCustomEditors, defaultCustomEditor } from '../common/contributedCustomEditors';

src/vs/workbench/contrib/files/browser/fileActions.contribution.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTI
1010
import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions';
1111
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
1212
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
13-
import { openWindowCommand, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand, ReadonlyEditorContext } from 'vs/workbench/contrib/files/browser/fileCommands';
13+
import { openWindowCommand, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand, ReadonlyEditorContext, OPEN_WITH_EXPLORER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileCommands';
1414
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
1515
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
1616
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
1717
import { isMacintosh } from 'vs/base/common/platform';
18-
import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files';
18+
import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext, ExplorerResourceAvailableEditorIdsContext } from 'vs/workbench/contrib/files/common/files';
1919
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands';
2020
import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
2121
import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
@@ -26,7 +26,7 @@ import { WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
2626
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
2727
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
2828
import { OpenFileFolderAction, OpenFileAction, OpenFolderAction, OpenWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions';
29-
import { ActiveEditorIsReadonlyContext, DirtyWorkingCopiesContext, ActiveEditorContext, ActiveEditorAvailableEditorsContext } from 'vs/workbench/common/editor';
29+
import { ActiveEditorIsReadonlyContext, DirtyWorkingCopiesContext, ActiveEditorContext, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/editor';
3030
import { SidebarFocusContext } from 'vs/workbench/common/viewlet';
3131
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
3232

@@ -36,7 +36,7 @@ const category = { value: nls.localize('filesCategory', "File"), original: 'File
3636
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
3737
registry.registerWorkbenchAction(SyncActionDescriptor.from(SaveAllAction, { primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category.value);
3838
registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalCompareResourcesAction), 'File: Compare Active File With...', category.value);
39-
registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenResourcesAction), 'File: Reopen With...', category.value, ActiveEditorAvailableEditorsContext);
39+
registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenResourcesAction), 'File: Reopen With...', category.value, ActiveEditorAvailableEditorIdsContext);
4040
registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusFilesExplorer), 'File: Focus on Files Explorer', category.value);
4141
registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowActiveFileInExplorer), 'File: Reveal Active File in Side Bar', category.value);
4242
registry.registerWorkbenchAction(SyncActionDescriptor.from(CollapseExplorerView), 'File: Collapse Folders in Explorer', category.value);
@@ -192,7 +192,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
192192
},
193193
group: '6_reopen',
194194
order: 20,
195-
when: ActiveEditorAvailableEditorsContext,
195+
when: ActiveEditorAvailableEditorIdsContext,
196196
});
197197

198198
// Editor Title Menu for Conflict Resolution
@@ -435,6 +435,16 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
435435
when: ContextKeyExpr.and(ExplorerFolderContext.toNegated(), ResourceContextKey.HasResource)
436436
});
437437

438+
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
439+
group: 'navigation',
440+
order: 20,
441+
command: {
442+
id: OPEN_WITH_EXPLORER_COMMAND_ID,
443+
title: nls.localize('explorerOpenWith', "Open With..."),
444+
},
445+
when: ContextKeyExpr.and(ExplorerRootContext.toNegated(), ExplorerResourceAvailableEditorIdsContext),
446+
});
447+
438448
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
439449
group: '3_compare',
440450
order: 20,

0 commit comments

Comments
 (0)