Skip to content

Commit 09fa374

Browse files
authored
Add a context menu to show/hide the minimap (microsoft#152850)
Fixes microsoft#148131: Add a context menu to show/hide the minimap
1 parent d257875 commit 09fa374

File tree

1 file changed

+134
-6
lines changed

1 file changed

+134
-6
lines changed

src/vs/editor/contrib/contextmenu/browser/contextmenu.ts

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
2525
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
2626
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2727
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
28+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2829

2930
export class ContextMenuController implements IEditorContribution {
3031

@@ -44,7 +45,8 @@ export class ContextMenuController implements IEditorContribution {
4445
@IContextViewService private readonly _contextViewService: IContextViewService,
4546
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
4647
@IKeybindingService private readonly _keybindingService: IKeybindingService,
47-
@IMenuService private readonly _menuService: IMenuService
48+
@IMenuService private readonly _menuService: IMenuService,
49+
@IConfigurationService private readonly _configurationService: IConfigurationService,
4850
) {
4951
this._editor = editor;
5052

@@ -98,6 +100,10 @@ export class ContextMenuController implements IEditorContribution {
98100
e.event.preventDefault();
99101
e.event.stopPropagation();
100102

103+
if (e.target.type === MouseTargetType.SCROLLBAR) {
104+
return this._showScrollbarContextMenu({ x: e.event.posx - 1, width: 2, y: e.event.posy - 1, height: 2 });
105+
}
106+
101107
if (e.target.type !== MouseTargetType.CONTENT_TEXT && e.target.type !== MouseTargetType.CONTENT_EMPTY && e.target.type !== MouseTargetType.TEXTAREA) {
102108
return; // only support mouse click into text or native context menu key for now
103109
}
@@ -138,11 +144,6 @@ export class ContextMenuController implements IEditorContribution {
138144
return;
139145
}
140146

141-
if (!this._contextMenuService) {
142-
this._editor.focus();
143-
return; // We need the context menu service to function
144-
}
145-
146147
// Find actions available for menu
147148
const menuActions = this._getMenuActions(this._editor.getModel(),
148149
this._editor.isSimpleWidget ? MenuId.SimpleEditorContext : MenuId.EditorContext);
@@ -257,6 +258,133 @@ export class ContextMenuController implements IEditorContribution {
257258
});
258259
}
259260

261+
private _showScrollbarContextMenu(anchor: IAnchor): void {
262+
if (!this._editor.hasModel()) {
263+
return;
264+
}
265+
266+
const minimapOptions = this._editor.getOption(EditorOption.minimap);
267+
268+
let lastId = 0;
269+
const createAction = (opts: { label: string; enabled?: boolean; checked?: boolean; run: () => void }): IAction => {
270+
return {
271+
id: `menu-action-${++lastId}`,
272+
label: opts.label,
273+
tooltip: '',
274+
class: undefined,
275+
enabled: (typeof opts.enabled === 'undefined' ? true : opts.enabled),
276+
checked: opts.checked,
277+
run: opts.run,
278+
dispose: () => null
279+
};
280+
};
281+
const createSubmenuAction = (label: string, actions: IAction[]): SubmenuAction => {
282+
return new SubmenuAction(
283+
`menu-action-${++lastId}`,
284+
label,
285+
actions,
286+
undefined
287+
);
288+
};
289+
const createEnumAction = <T>(label: string, enabled: boolean, configName: string, configuredValue: T, options: { label: string; value: T }[]): IAction => {
290+
if (!enabled) {
291+
return createAction({ label, enabled, run: () => { } });
292+
}
293+
const createRunner = (value: T) => {
294+
return () => {
295+
this._configurationService.updateValue(configName, value);
296+
};
297+
};
298+
const actions: IAction[] = [];
299+
for (const option of options) {
300+
actions.push(createAction({
301+
label: option.label,
302+
checked: configuredValue === option.value,
303+
run: createRunner(option.value)
304+
}));
305+
}
306+
return createSubmenuAction(
307+
label,
308+
actions
309+
);
310+
};
311+
312+
const actions: IAction[] = [];
313+
actions.push(createAction({
314+
label: nls.localize('context.minimap.showMinimap', "Show Minimap"),
315+
checked: minimapOptions.enabled,
316+
run: () => {
317+
this._configurationService.updateValue(`editor.minimap.enabled`, !minimapOptions.enabled);
318+
}
319+
}));
320+
actions.push(new Separator());
321+
actions.push(createAction({
322+
label: nls.localize('context.minimap.renderCharacters', "Render Characters"),
323+
enabled: minimapOptions.enabled,
324+
checked: minimapOptions.renderCharacters,
325+
run: () => {
326+
this._configurationService.updateValue(`editor.minimap.renderCharacters`, !minimapOptions.renderCharacters);
327+
}
328+
}));
329+
actions.push(createEnumAction<'proportional' | 'fill' | 'fit'>(
330+
nls.localize('context.minimap.size', "Size"),
331+
minimapOptions.enabled,
332+
'editor.minimap.size',
333+
minimapOptions.size,
334+
[{
335+
label: nls.localize('context.minimap.size.proportional', "Proportional"),
336+
value: 'proportional'
337+
}, {
338+
label: nls.localize('context.minimap.size.fill', "Fill"),
339+
value: 'fill'
340+
}, {
341+
label: nls.localize('context.minimap.size.fit', "Fit"),
342+
value: 'fit'
343+
}]
344+
));
345+
actions.push(createEnumAction<number>(
346+
nls.localize('context.minimap.scale', "Scale"),
347+
minimapOptions.enabled,
348+
'editor.minimap.scale',
349+
minimapOptions.scale,
350+
[{
351+
label: nls.localize('context.minimap.scale.1', "1"),
352+
value: 1
353+
}, {
354+
label: nls.localize('context.minimap.scale.2', "2"),
355+
value: 2
356+
}, {
357+
label: nls.localize('context.minimap.scale.3', "3"),
358+
value: 3
359+
}]
360+
));
361+
actions.push(createEnumAction<'always' | 'mouseover'>(
362+
nls.localize('context.minimap.slider', "Slider"),
363+
minimapOptions.enabled,
364+
'editor.minimap.showSlider',
365+
minimapOptions.showSlider,
366+
[{
367+
label: nls.localize('context.minimap.slider.mouseover', "Mouse Over"),
368+
value: 'mouseover'
369+
}, {
370+
label: nls.localize('context.minimap.slider.always', "Always"),
371+
value: 'always'
372+
}]
373+
));
374+
375+
const useShadowDOM = this._editor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035
376+
this._contextMenuIsBeingShownCount++;
377+
this._contextMenuService.showContextMenu({
378+
domForShadowRoot: useShadowDOM ? this._editor.getDomNode() : undefined,
379+
getAnchor: () => anchor,
380+
getActions: () => actions,
381+
onHide: (wasCancelled: boolean) => {
382+
this._contextMenuIsBeingShownCount--;
383+
this._editor.focus();
384+
}
385+
});
386+
}
387+
260388
private _keybindingFor(action: IAction): ResolvedKeybinding | undefined {
261389
return this._keybindingService.lookupKeybinding(action.id);
262390
}

0 commit comments

Comments
 (0)