Skip to content

Commit 337cd4b

Browse files
authored
Expose editor "blue button" as menu (microsoft#158740)
* Expose editor "blue button" as menu * rename proposed `MergeToolbar` to `EditorContent` menu * adopt GIT and sync conflicts usage * use content menu for "open in 3wm" command * add new `ctxIsMergeResultEditor` context key Better fix for microsoft#153800 * fix typo
1 parent 4162134 commit 337cd4b

File tree

11 files changed

+79
-50
lines changed

11 files changed

+79
-50
lines changed

extensions/git/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255",
1212
"enabledApiProposals": [
1313
"diffCommand",
14-
"contribMergeEditorToolbar",
14+
"contribEditorContentMenu",
1515
"contribViewsWelcome",
1616
"editSessionIdentityProvider",
1717
"scmActionButton",
@@ -1514,11 +1514,6 @@
15141514
"group": "navigation",
15151515
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && !isInDiffEditor && !isMergeEditor && resourceScheme == file && scmActiveResourceHasChanges"
15161516
},
1517-
{
1518-
"command": "git.openMergeEditor",
1519-
"group": "navigation@-10",
1520-
"when": "config.git.enabled && !git.missing && !isInDiffEditor && !isMergeEditor && resource in git.mergeChanges"
1521-
},
15221517
{
15231518
"command": "git.commitMessageAccept",
15241519
"group": "navigation",
@@ -1562,10 +1557,15 @@
15621557
"when": "isInDiffRightEditor && !isInEmbeddedDiffEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
15631558
}
15641559
],
1565-
"merge/toolbar": [
1560+
"editor/content": [
15661561
{
15671562
"command": "git.acceptMerge",
1568-
"when": "isMergeEditor && mergeEditorBaseUri =~ /^(git|file):/ && mergeEditorResultUri in git.mergeChanges"
1563+
"when": "isMergeResultEditor && mergeEditorBaseUri =~ /^(git|file):/ && mergeEditorResultUri in git.mergeChanges"
1564+
},
1565+
{
1566+
"command": "git.openMergeEditor",
1567+
"group": "navigation@-10",
1568+
"when": "config.git.enabled && !git.missing && !isInDiffEditor && !isMergeEditor && resource in git.mergeChanges"
15691569
}
15701570
],
15711571
"scm/change/title": [

src/vs/platform/actions/common/actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export class MenuId {
5757
static readonly DebugToolBarStop = new MenuId('DebugToolBarStop');
5858
static readonly EditorContext = new MenuId('EditorContext');
5959
static readonly SimpleEditorContext = new MenuId('SimpleEditorContext');
60+
static readonly EditorContent = new MenuId('EditorContent');
6061
static readonly EditorContextCopy = new MenuId('EditorContextCopy');
6162
static readonly EditorContextPeek = new MenuId('EditorContextPeek');
6263
static readonly EditorContextShare = new MenuId('EditorContextShare');
@@ -165,7 +166,6 @@ export class MenuId {
165166
static readonly WebviewContext = new MenuId('WebviewContext');
166167
static readonly InlineCompletionsActions = new MenuId('InlineCompletionsActions');
167168
static readonly NewFile = new MenuId('NewFile');
168-
static readonly MergeToolbar = new MenuId('MergeToolbar');
169169
static readonly MergeInput1Toolbar = new MenuId('MergeToolbar1Toolbar');
170170
static readonly MergeInput2Toolbar = new MenuId('MergeToolbar2Toolbar');
171171

src/vs/workbench/browser/codeeditor.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/commo
2626
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
2727
import { TrackedRangeStickiness, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
2828
import { EditorOption } from 'vs/editor/common/config/editorOptions';
29+
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
30+
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
31+
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
32+
import { IAction } from 'vs/base/common/actions';
2933

3034
export interface IRangeHighlightDecoration {
3135
resource: URI;
@@ -212,6 +216,44 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
212216
}
213217
}
214218

219+
export class FloatingClickMenu extends Disposable implements IEditorContribution {
220+
221+
static readonly ID = 'editor.contrib.floatingClickMenu';
222+
223+
constructor(
224+
editor: ICodeEditor,
225+
@IInstantiationService instantiationService: IInstantiationService,
226+
@IMenuService menuService: IMenuService,
227+
@IContextKeyService contextKeyService: IContextKeyService
228+
) {
229+
super();
230+
231+
const menu = menuService.createMenu(MenuId.EditorContent, contextKeyService);
232+
const menuDisposables = new DisposableStore();
233+
const renderMenuAsFloatingClickBtn = () => {
234+
menuDisposables.clear();
235+
if (!editor.hasModel() || editor.getOption(EditorOption.inDiffEditor)) {
236+
return;
237+
}
238+
const actions: IAction[] = [];
239+
createAndFillInActionBarActions(menu, { renderShortTitle: true, shouldForwardArgs: true }, actions);
240+
if (actions.length === 0) {
241+
return;
242+
}
243+
// todo@jrieken find a way to handle N actions, like showing a context menu
244+
const [first] = actions;
245+
const widget = instantiationService.createInstance(FloatingClickWidget, editor, first.label, first.id);
246+
menuDisposables.add(widget);
247+
menuDisposables.add(widget.onClick(() => first.run(editor.getModel().uri)));
248+
widget.render();
249+
};
250+
this._store.add(menu);
251+
this._store.add(menuDisposables);
252+
this._store.add(menu.onDidChange(renderMenuAsFloatingClickBtn));
253+
renderMenuAsFloatingClickBtn();
254+
}
255+
}
256+
215257
export class OpenWorkspaceButtonContribution extends Disposable implements IEditorContribution {
216258

217259
static get(editor: ICodeEditor): OpenWorkspaceButtonContribution | null {

src/vs/workbench/browser/parts/editor/editor.contribution.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
5454
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
5555
import { isMacintosh } from 'vs/base/common/platform';
5656
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
57-
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/codeeditor';
57+
import { FloatingClickMenu, OpenWorkspaceButtonContribution } from 'vs/workbench/browser/codeeditor';
5858
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
5959
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
6060
import { EditorAutoSave } from 'vs/workbench/browser/parts/editor/editorAutoSave';
@@ -127,6 +127,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
127127
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledTextEditorWorkingCopyEditorHandler, LifecyclePhase.Ready);
128128
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DynamicEditorResolverConfigurations, LifecyclePhase.Ready);
129129

130+
registerEditorContribution(FloatingClickMenu.ID, FloatingClickMenu);
130131
registerEditorContribution(OpenWorkspaceButtonContribution.ID, OpenWorkspaceButtonContribution);
131132

132133
//#endregion

src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55

66
import { CompareResult } from 'vs/base/common/arrays';
77
import { BugIndicatingError } from 'vs/base/common/errors';
8+
import { toDisposable } from 'vs/base/common/lifecycle';
89
import { autorun, derived } from 'vs/base/common/observable';
910
import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model';
1011
import { localize } from 'vs/nls';
12+
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1113
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1214
import { MergeMarkersController } from 'vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController';
1315
import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';
1416
import { applyObservableDecorations, join } from 'vs/workbench/contrib/mergeEditor/browser/utils';
1517
import { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors';
1618
import { EditorGutter } from 'vs/workbench/contrib/mergeEditor/browser/view/editorGutter';
19+
import { ctxIsMergeResultEditor } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
1720
import { CodeEditorView } from './codeEditorView';
1821

1922
export class ResultCodeEditorView extends CodeEditorView {
@@ -110,6 +113,13 @@ export class ResultCodeEditorView extends CodeEditorView {
110113
) {
111114
super(instantiationService);
112115

116+
this.editor.invokeWithinContext(accessor => {
117+
const contextKeyService = accessor.get(IContextKeyService);
118+
const isMergeResultEditor = ctxIsMergeResultEditor.bindTo(contextKeyService);
119+
isMergeResultEditor.set(true);
120+
this._register(toDisposable(() => isMergeResultEditor.reset()));
121+
});
122+
113123
this._register(applyObservableDecorations(this.editor, this.decorations));
114124

115125
this._register(new MergeMarkersController(this.editor, this.viewModel));

src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { $, Dimension, reset } from 'vs/base/browser/dom';
77
import { Direction, Grid, IView, SerializableGrid } from 'vs/base/browser/ui/grid/grid';
88
import { Orientation, Sizing } from 'vs/base/browser/ui/splitview/splitview';
9-
import { IAction } from 'vs/base/common/actions';
109
import { CancellationToken } from 'vs/base/common/cancellation';
1110
import { Color } from 'vs/base/common/color';
1211
import { BugIndicatingError } from 'vs/base/common/errors';
@@ -23,8 +22,7 @@ import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/ed
2322
import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
2423
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
2524
import { localize } from 'vs/nls';
26-
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
27-
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
25+
import { MenuId } from 'vs/platform/actions/common/actions';
2826
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2927
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
3028
import { IEditorOptions, ITextEditorOptions, ITextResourceEditorInput } from 'vs/platform/editor/common/editor';
@@ -34,7 +32,6 @@ import { ILabelService } from 'vs/platform/label/common/label';
3432
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
3533
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
3634
import { IThemeService } from 'vs/platform/theme/common/themeService';
37-
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
3835
import { AbstractTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
3936
import { DEFAULT_EDITOR_ASSOCIATION, EditorInputWithOptions, IEditorOpenContext, IResourceMergeEditorInput } from 'vs/workbench/common/editor';
4037
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
@@ -108,8 +105,7 @@ export class MergeEditor extends AbstractTextEditor<IMergeEditorViewState> {
108105
constructor(
109106
@IInstantiationService instantiation: IInstantiationService,
110107
@ILabelService private readonly _labelService: ILabelService,
111-
@IMenuService private readonly _menuService: IMenuService,
112-
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
108+
@IContextKeyService contextKeyService: IContextKeyService,
113109
@ITelemetryService telemetryService: ITelemetryService,
114110
@IStorageService storageService: IStorageService,
115111
@IThemeService themeService: IThemeService,
@@ -122,10 +118,10 @@ export class MergeEditor extends AbstractTextEditor<IMergeEditorViewState> {
122118
) {
123119
super(MergeEditor.ID, telemetryService, instantiation, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService, fileService);
124120

125-
this._ctxIsMergeEditor = ctxIsMergeEditor.bindTo(_contextKeyService);
126-
this._ctxUsesColumnLayout = ctxMergeEditorLayout.bindTo(_contextKeyService);
127-
this._ctxBaseUri = ctxMergeBaseUri.bindTo(_contextKeyService);
128-
this._ctxResultUri = ctxMergeResultUri.bindTo(_contextKeyService);
121+
this._ctxIsMergeEditor = ctxIsMergeEditor.bindTo(contextKeyService);
122+
this._ctxUsesColumnLayout = ctxMergeEditorLayout.bindTo(contextKeyService);
123+
this._ctxBaseUri = ctxMergeBaseUri.bindTo(contextKeyService);
124+
this._ctxResultUri = ctxMergeResultUri.bindTo(contextKeyService);
129125

130126
this._layoutMode = instantiation.createInstance(MergeEditorLayout);
131127
this._ctxUsesColumnLayout.set(this._layoutMode.value);
@@ -169,27 +165,6 @@ export class MergeEditor extends AbstractTextEditor<IMergeEditorViewState> {
169165
})
170166
)
171167
);
172-
173-
// TODO@jrieken make this proper: add menu id and allow extensions to contribute
174-
const toolbarMenu = this._menuService.createMenu(MenuId.MergeToolbar, this._contextKeyService);
175-
const toolbarMenuDisposables = new DisposableStore();
176-
const toolbarMenuRender = () => {
177-
toolbarMenuDisposables.clear();
178-
179-
const actions: IAction[] = [];
180-
createAndFillInActionBarActions(toolbarMenu, { renderShortTitle: true, shouldForwardArgs: true }, actions);
181-
if (actions.length > 0) {
182-
const [first] = actions;
183-
const acceptBtn = this.instantiationService.createInstance(FloatingClickWidget, this.inputResultView.editor, first.label, first.id);
184-
toolbarMenuDisposables.add(acceptBtn.onClick(() => first.run(this.inputResultView.editor.getModel()?.uri)));
185-
toolbarMenuDisposables.add(acceptBtn);
186-
acceptBtn.render();
187-
}
188-
};
189-
this._store.add(toolbarMenu);
190-
this._store.add(toolbarMenuDisposables);
191-
this._store.add(toolbarMenu.onDidChange(toolbarMenuRender));
192-
toolbarMenuRender();
193168
}
194169

195170
private updateResultScrolling(scrollTopChanged: boolean, scrollLeftChanged: boolean): void {

src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
99
export type MergeEditorLayoutTypes = 'mixed' | 'columns';
1010

1111
export const ctxIsMergeEditor = new RawContextKey<boolean>('isMergeEditor', false, { type: 'boolean', description: localize('is', 'The editor is a merge editor') });
12+
export const ctxIsMergeResultEditor = new RawContextKey<boolean>('isMergeResultEditor', false, { type: 'boolean', description: localize('isr', 'The editor is a the result editor of a merge editor.') });
1213
export const ctxMergeEditorLayout = new RawContextKey<MergeEditorLayoutTypes>('mergeEditorLayout', 'mixed', { type: 'string', description: localize('editorLayout', 'The layout mode of a merge editor') });
1314
export const ctxMergeBaseUri = new RawContextKey<string>('mergeEditorBaseUri', '', { type: 'string', description: localize('baseUri', 'The uri of the baser of a merge editor') });
1415
export const ctxMergeResultUri = new RawContextKey<string>('mergeEditorResultUri', '', { type: 'string', description: localize('resultUri', 'The uri of the result of a merge editor') });

src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ import { MarkdownString } from 'vs/base/common/htmlContent';
5858
import { IHostService } from 'vs/workbench/services/host/browser/host';
5959
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
6060
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
61-
import { ctxIsMergeEditor, ctxMergeBaseUri } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
61+
import { ctxIsMergeResultEditor, ctxMergeBaseUri } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
6262

6363
const CONTEXT_CONFLICTS_SOURCES = new RawContextKey<string>('conflictsSources', '');
6464

@@ -1287,8 +1287,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
12871287
id: 'workbench.userDataSync.actions.acceptMerges',
12881288
title: localize('accept merges title', "Accept Merge"),
12891289
menu: [{
1290-
id: MenuId.MergeToolbar,
1291-
when: ContextKeyExpr.and(ctxIsMergeEditor, ContextKeyExpr.regex(ctxMergeBaseUri.key, new RegExp(`^${USER_DATA_SYNC_SCHEME}:`))),
1290+
id: MenuId.EditorContent,
1291+
when: ContextKeyExpr.and(ctxIsMergeResultEditor, ContextKeyExpr.regex(ctxMergeBaseUri.key, new RegExp(`^${USER_DATA_SYNC_SCHEME}:`))),
12921292
}],
12931293
});
12941294
}

src/vs/workbench/services/actions/common/menusExtensionPoint.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,10 @@ const apiMenus: IAPIMenu[] = [
280280
proposed: 'inlineCompletionsAdditions'
281281
},
282282
{
283-
key: 'merge/toolbar',
284-
id: MenuId.MergeToolbar,
285-
description: localize('merge.toolbar', "The prominent botton in the merge editor"),
286-
proposed: 'contribMergeEditorToolbar'
283+
key: 'editor/content',
284+
id: MenuId.EditorContent,
285+
description: localize('merge.toolbar', "The prominent button in an editor, overlays its content"),
286+
proposed: 'contribEditorContentMenu'
287287
},
288288
{
289289
key: 'webview/context',

src/vs/workbench/services/extensions/common/extensionsApiProposals.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ export const allApiProposals = Object.freeze({
1111
commentsResolvedState: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentsResolvedState.d.ts',
1212
contribCommentPeekContext: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentPeekContext.d.ts',
1313
contribEditSessions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditSessions.d.ts',
14+
contribEditorContentMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditorContentMenu.d.ts',
1415
contribLabelFormatterWorkspaceTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLabelFormatterWorkspaceTooltip.d.ts',
1516
contribMenuBarHome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMenuBarHome.d.ts',
16-
contribMergeEditorToolbar: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMergeEditorToolbar.d.ts',
1717
contribRemoteHelp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts',
1818
contribShareMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts',
1919
contribViewSize: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewSize.d.ts',

0 commit comments

Comments
 (0)